1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    Copyright (C) Matthew Chapman 1999-2005
4 
5    This program 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 2 of the License, or
8    (at your option) any later version.
9 
10    This program 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 along
16    with this program; if not, write to the Free Software Foundation, Inc.,
17    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 /*
21   Here are some resources, for your IRP hacking pleasure:
22 
23   http://cvs.sourceforge.net/viewcvs.py/mingw/w32api/include/ddk/winddk.h?view=markup
24 
25   http://win32.mvps.org/ntfs/streams.cpp
26 
27   http://www.acc.umu.se/~bosse/ntifs.h
28 
29   http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/File/
30 
31   http://us1.samba.org/samba/ftp/specs/smb-nt01.txt
32 
33   http://www.osronline.com/
34 */
35 
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <sys/time.h>
39 #include <dirent.h>		/* opendir, closedir, readdir */
40 #include <time.h>
41 #include <errno.h>
42 #include "rdesktop.h"
43 
44 #define IRP_MJ_CREATE			0x00
45 #define IRP_MJ_CLOSE			0x02
46 #define IRP_MJ_READ			0x03
47 #define IRP_MJ_WRITE			0x04
48 #define	IRP_MJ_QUERY_INFORMATION	0x05
49 #define IRP_MJ_SET_INFORMATION		0x06
50 #define IRP_MJ_QUERY_VOLUME_INFORMATION	0x0a
51 #define IRP_MJ_DIRECTORY_CONTROL	0x0c
52 #define IRP_MJ_DEVICE_CONTROL		0x0e
53 #define IRP_MJ_LOCK_CONTROL             0x11
54 
55 #define IRP_MN_QUERY_DIRECTORY          0x01
56 #define IRP_MN_NOTIFY_CHANGE_DIRECTORY  0x02
57 
58 extern DEVICE_FNS serial_fns;
59 extern DEVICE_FNS printer_fns;
60 extern DEVICE_FNS parallel_fns;
61 extern DEVICE_FNS disk_fns;
62 
63 /* Return device_id for a given handle */
64 int
get_device_index(RDPCLIENT * This,NTHANDLE handle)65 get_device_index(RDPCLIENT * This, NTHANDLE handle)
66 {
67 	int i;
68 	for (i = 0; i < RDPDR_MAX_DEVICES; i++)
69 	{
70 		if (This->rdpdr_device[i].handle == handle)
71 			return i;
72 	}
73 	return -1;
74 }
75 
76 /* Converts a windows path to a unix path */
77 void
convert_to_unix_filename(char * filename)78 convert_to_unix_filename(char *filename)
79 {
80 	char *p;
81 
82 	while ((p = strchr(filename, '\\')))
83 	{
84 		*p = '/';
85 	}
86 }
87 
88 static BOOL
rdpdr_handle_ok(RDPCLIENT * This,int device,int handle)89 rdpdr_handle_ok(RDPCLIENT * This, int device, int handle)
90 {
91 	switch (This->rdpdr_device[device].device_type)
92 	{
93 		case DEVICE_TYPE_PARALLEL:
94 		case DEVICE_TYPE_SERIAL:
95 		case DEVICE_TYPE_PRINTER:
96 		case DEVICE_TYPE_SCARD:
97 			if (This->rdpdr_device[device].handle != handle)
98 				return False;
99 			break;
100 		case DEVICE_TYPE_DISK:
101 			if (This->fileinfo[handle].device_id != device)
102 				return False;
103 			break;
104 	}
105 	return True;
106 }
107 
108 /* Add a new io request to the table containing pending io requests so it won't block rdesktop */
109 static BOOL
add_async_iorequest(RDPCLIENT * This,uint32 device,uint32 file,uint32 id,uint32 major,uint32 length,DEVICE_FNS * fns,uint32 total_timeout,uint32 interval_timeout,uint8 * buffer,uint32 offset)110 add_async_iorequest(RDPCLIENT * This, uint32 device, uint32 file, uint32 id, uint32 major, uint32 length,
111 		    DEVICE_FNS * fns, uint32 total_timeout, uint32 interval_timeout, uint8 * buffer,
112 		    uint32 offset)
113 {
114 	struct async_iorequest *iorq;
115 
116 	if (This->iorequest == NULL)
117 	{
118 		This->iorequest = (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
119 		if (!This->iorequest)
120 			return False;
121 		This->iorequest->fd = 0;
122 		This->iorequest->next = NULL;
123 	}
124 
125 	iorq = This->iorequest;
126 
127 	while (iorq->fd != 0)
128 	{
129 		/* create new element if needed */
130 		if (iorq->next == NULL)
131 		{
132 			iorq->next =
133 				(struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
134 			if (!iorq->next)
135 				return False;
136 			iorq->next->fd = 0;
137 			iorq->next->next = NULL;
138 		}
139 		iorq = iorq->next;
140 	}
141 	iorq->device = device;
142 	iorq->fd = file;
143 	iorq->id = id;
144 	iorq->major = major;
145 	iorq->length = length;
146 	iorq->partial_len = 0;
147 	iorq->fns = fns;
148 	iorq->timeout = total_timeout;
149 	iorq->itv_timeout = interval_timeout;
150 	iorq->buffer = buffer;
151 	iorq->offset = offset;
152 	return True;
153 }
154 
155 static void
rdpdr_send_connect(RDPCLIENT * This)156 rdpdr_send_connect(RDPCLIENT * This)
157 {
158 	uint8 magic[4] = "rDCC";
159 	STREAM s;
160 
161 	s = channel_init(This, This->rdpdr.channel, 12);
162 	out_uint8a(s, magic, 4);
163 	out_uint16_le(s, 1);	/* unknown */
164 	out_uint16_le(s, 5);
165 	out_uint32_be(s, 0x815ed39d);	/* IP address (use 127.0.0.1) 0x815ed39d */
166 	s_mark_end(s);
167 	channel_send(This, s, This->rdpdr.channel);
168 }
169 
170 
171 static void
rdpdr_send_name(RDPCLIENT * This)172 rdpdr_send_name(RDPCLIENT * This)
173 {
174 	uint8 magic[4] = "rDNC";
175 	STREAM s;
176 	uint32 hostlen;
177 
178 	if (NULL == This->rdpdr_clientname)
179 	{
180 		This->rdpdr_clientname = This->hostname;
181 	}
182 	hostlen = (strlen(This->rdpdr_clientname) + 1) * 2;
183 
184 	s = channel_init(This, This->rdpdr.channel, 16 + hostlen);
185 	out_uint8a(s, magic, 4);
186 	out_uint16_le(s, 0x63);	/* unknown */
187 	out_uint16_le(s, 0x72);
188 	out_uint32(s, 0);
189 	out_uint32_le(s, hostlen);
190 	rdp_out_unistr(This, s, This->rdpdr_clientname, hostlen - 2);
191 	s_mark_end(s);
192 	channel_send(This, s, This->rdpdr.channel);
193 }
194 
195 /* Returns the size of the payload of the announce packet */
196 static int
announcedata_size(RDPCLIENT * This)197 announcedata_size(RDPCLIENT * This)
198 {
199 	int size, i;
200 	PRINTER *printerinfo;
201 
202 	size = 8;		/* static announce size */
203 	size += This->num_devices * 0x14;
204 
205 	for (i = 0; i < This->num_devices; i++)
206 	{
207 		if (This->rdpdr_device[i].device_type == DEVICE_TYPE_PRINTER)
208 		{
209 			printerinfo = (PRINTER *) This->rdpdr_device[i].pdevice_data;
210 			printerinfo->bloblen =
211 				printercache_load_blob(printerinfo->printer, &(printerinfo->blob));
212 
213 			size += 0x18;
214 			size += 2 * strlen(printerinfo->driver) + 2;
215 			size += 2 * strlen(printerinfo->printer) + 2;
216 			size += printerinfo->bloblen;
217 		}
218 	}
219 
220 	return size;
221 }
222 
223 static void
rdpdr_send_available(RDPCLIENT * This)224 rdpdr_send_available(RDPCLIENT * This)
225 {
226 
227 	uint8 magic[4] = "rDAD";
228 	uint32 driverlen, printerlen, bloblen;
229 	int i;
230 	STREAM s;
231 	PRINTER *printerinfo;
232 
233 	s = channel_init(This, This->rdpdr.channel, announcedata_size(This));
234 	out_uint8a(s, magic, 4);
235 	out_uint32_le(s, This->num_devices);
236 
237 	for (i = 0; i < This->num_devices; i++)
238 	{
239 		out_uint32_le(s, This->rdpdr_device[i].device_type);
240 		out_uint32_le(s, i);	/* RDP Device ID */
241 		/* Is it possible to use share names longer than 8 chars?
242 		   /astrand */
243 		out_uint8p(s, This->rdpdr_device[i].name, 8);
244 
245 		switch (This->rdpdr_device[i].device_type)
246 		{
247 			case DEVICE_TYPE_PRINTER:
248 				printerinfo = (PRINTER *) This->rdpdr_device[i].pdevice_data;
249 
250 				driverlen = 2 * strlen(printerinfo->driver) + 2;
251 				printerlen = 2 * strlen(printerinfo->printer) + 2;
252 				bloblen = printerinfo->bloblen;
253 
254 				out_uint32_le(s, 24 + driverlen + printerlen + bloblen);	/* length of extra info */
255 				out_uint32_le(s, printerinfo->default_printer ? 2 : 0);
256 				out_uint8s(s, 8);	/* unknown */
257 				out_uint32_le(s, driverlen);
258 				out_uint32_le(s, printerlen);
259 				out_uint32_le(s, bloblen);
260 				rdp_out_unistr(This, s, printerinfo->driver, driverlen - 2);
261 				rdp_out_unistr(This, s, printerinfo->printer, printerlen - 2);
262 				out_uint8a(s, printerinfo->blob, bloblen);
263 
264 				if (printerinfo->blob)
265 					xfree(printerinfo->blob);	/* Blob is sent twice if reconnecting */
266 				break;
267 			default:
268 				out_uint32(s, 0);
269 		}
270 	}
271 #if 0
272 	out_uint32_le(s, 0x20);	/* Device type 0x20 - smart card */
273 	out_uint32_le(s, 0);
274 	out_uint8p(s, "SCARD", 5);
275 	out_uint8s(s, 3);
276 	out_uint32(s, 0);
277 #endif
278 
279 	s_mark_end(s);
280 	channel_send(This, s, This->rdpdr.channel);
281 }
282 
283 static void
rdpdr_send_completion(RDPCLIENT * This,uint32 device,uint32 id,uint32 status,uint32 result,uint8 * buffer,uint32 length)284 rdpdr_send_completion(RDPCLIENT * This, uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
285 		      uint32 length)
286 {
287 	uint8 magic[4] = "rDCI";
288 	STREAM s;
289 
290 	s = channel_init(This, This->rdpdr.channel, 20 + length);
291 	out_uint8a(s, magic, 4);
292 	out_uint32_le(s, device);
293 	out_uint32_le(s, id);
294 	out_uint32_le(s, status);
295 	out_uint32_le(s, result);
296 	out_uint8p(s, buffer, length);
297 	s_mark_end(s);
298 	/* JIF */
299 #ifdef WITH_DEBUG_RDP5
300 	printf("--> rdpdr_send_completion\n");
301 	/* hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
302 #endif
303 	channel_send(This, s, This->rdpdr.channel);
304 }
305 
306 static void
rdpdr_process_irp(RDPCLIENT * This,STREAM s)307 rdpdr_process_irp(RDPCLIENT * This, STREAM s)
308 {
309 	uint32 result = 0,
310 		length = 0,
311 		desired_access = 0,
312 		request,
313 		file,
314 		info_level,
315 		buffer_len,
316 		id,
317 		major,
318 		minor,
319 		device,
320 		offset,
321 		bytes_in,
322 		bytes_out,
323 		error_mode,
324 		share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0;
325 
326 	char filename[PATH_MAX];
327 	uint8 *buffer, *pst_buf;
328 	struct stream out;
329 	DEVICE_FNS *fns;
330 	BOOL rw_blocking = True;
331 	NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
332 
333 	in_uint32_le(s, device);
334 	in_uint32_le(s, file);
335 	in_uint32_le(s, id);
336 	in_uint32_le(s, major);
337 	in_uint32_le(s, minor);
338 
339 	buffer_len = 0;
340 	buffer = (uint8 *) xmalloc(1024);
341 	buffer[0] = 0;
342 
343 	switch (This->rdpdr_device[device].device_type)
344 	{
345 		case DEVICE_TYPE_SERIAL:
346 
347 			fns = &serial_fns;
348 			rw_blocking = False;
349 			break;
350 
351 		case DEVICE_TYPE_PARALLEL:
352 
353 			fns = &parallel_fns;
354 			rw_blocking = False;
355 			break;
356 
357 		case DEVICE_TYPE_PRINTER:
358 
359 			fns = &printer_fns;
360 			break;
361 
362 		case DEVICE_TYPE_DISK:
363 
364 			fns = &disk_fns;
365 			rw_blocking = False;
366 			break;
367 
368 		case DEVICE_TYPE_SCARD:
369 		default:
370 
371 			error("IRP for bad device %ld\n", device);
372 			return;
373 	}
374 
375 	switch (major)
376 	{
377 		case IRP_MJ_CREATE:
378 
379 			in_uint32_be(s, desired_access);
380 			in_uint8s(s, 0x08);	/* unknown */
381 			in_uint32_le(s, error_mode);
382 			in_uint32_le(s, share_mode);
383 			in_uint32_le(s, disposition);
384 			in_uint32_le(s, flags_and_attributes);
385 			in_uint32_le(s, length);
386 
387 			if (length && (length / 2) < 256)
388 			{
389 				rdp_in_unistr(This, s, filename, length);
390 				convert_to_unix_filename(filename);
391 			}
392 			else
393 			{
394 				filename[0] = 0;
395 			}
396 
397 			if (!fns->create)
398 			{
399 				status = STATUS_NOT_SUPPORTED;
400 				break;
401 			}
402 
403 			status = fns->create(This, device, desired_access, share_mode, disposition,
404 					     flags_and_attributes, filename, &result);
405 			buffer_len = 1;
406 			break;
407 
408 		case IRP_MJ_CLOSE:
409 			if (!fns->close)
410 			{
411 				status = STATUS_NOT_SUPPORTED;
412 				break;
413 			}
414 
415 			status = fns->close(This, file);
416 			break;
417 
418 		case IRP_MJ_READ:
419 
420 			if (!fns->read)
421 			{
422 				status = STATUS_NOT_SUPPORTED;
423 				break;
424 			}
425 
426 			in_uint32_le(s, length);
427 			in_uint32_le(s, offset);
428 #if WITH_DEBUG_RDP5
429 			DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length, offset));
430 #endif
431 			if (!rdpdr_handle_ok(This, device, file))
432 			{
433 				status = STATUS_INVALID_HANDLE;
434 				break;
435 			}
436 
437 			if (rw_blocking)	/* Complete read immediately */
438 			{
439 				buffer = (uint8 *) xrealloc((void *) buffer, length);
440 				if (!buffer)
441 				{
442 					status = STATUS_CANCELLED;
443 					break;
444 				}
445 				status = fns->read(This, file, buffer, length, offset, &result);
446 				buffer_len = result;
447 				break;
448 			}
449 
450 			/* Add request to table */
451 			pst_buf = (uint8 *) xmalloc(length);
452 			if (!pst_buf)
453 			{
454 				status = STATUS_CANCELLED;
455 				break;
456 			}
457 			serial_get_timeout(This, file, length, &total_timeout, &interval_timeout);
458 			if (add_async_iorequest
459 			    (This, device, file, id, major, length, fns, total_timeout, interval_timeout,
460 			     pst_buf, offset))
461 			{
462 				status = STATUS_PENDING;
463 				break;
464 			}
465 
466 			status = STATUS_CANCELLED;
467 			break;
468 		case IRP_MJ_WRITE:
469 
470 			buffer_len = 1;
471 
472 			if (!fns->write)
473 			{
474 				status = STATUS_NOT_SUPPORTED;
475 				break;
476 			}
477 
478 			in_uint32_le(s, length);
479 			in_uint32_le(s, offset);
480 			in_uint8s(s, 0x18);
481 #if WITH_DEBUG_RDP5
482 			DEBUG(("RDPDR IRP Write (length: %d)\n", result));
483 #endif
484 			if (!rdpdr_handle_ok(This, device, file))
485 			{
486 				status = STATUS_INVALID_HANDLE;
487 				break;
488 			}
489 
490 			if (rw_blocking)	/* Complete immediately */
491 			{
492 				status = fns->write(This, file, s->p, length, offset, &result);
493 				break;
494 			}
495 
496 			/* Add to table */
497 			pst_buf = (uint8 *) xmalloc(length);
498 			if (!pst_buf)
499 			{
500 				status = STATUS_CANCELLED;
501 				break;
502 			}
503 
504 			in_uint8a(s, pst_buf, length);
505 
506 			if (add_async_iorequest
507 			    (This, device, file, id, major, length, fns, 0, 0, pst_buf, offset))
508 			{
509 				status = STATUS_PENDING;
510 				break;
511 			}
512 
513 			status = STATUS_CANCELLED;
514 			break;
515 
516 		case IRP_MJ_QUERY_INFORMATION:
517 
518 			if (This->rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
519 			{
520 				status = STATUS_INVALID_HANDLE;
521 				break;
522 			}
523 			in_uint32_le(s, info_level);
524 
525 			out.data = out.p = buffer;
526 			out.size = sizeof(buffer);
527 			status = disk_query_information(This, file, info_level, &out);
528 			result = buffer_len = out.p - out.data;
529 
530 			break;
531 
532 		case IRP_MJ_SET_INFORMATION:
533 
534 			if (This->rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
535 			{
536 				status = STATUS_INVALID_HANDLE;
537 				break;
538 			}
539 
540 			in_uint32_le(s, info_level);
541 
542 			out.data = out.p = buffer;
543 			out.size = sizeof(buffer);
544 			status = disk_set_information(This, file, info_level, s, &out);
545 			result = buffer_len = out.p - out.data;
546 			break;
547 
548 		case IRP_MJ_QUERY_VOLUME_INFORMATION:
549 
550 			if (This->rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
551 			{
552 				status = STATUS_INVALID_HANDLE;
553 				break;
554 			}
555 
556 			in_uint32_le(s, info_level);
557 
558 			out.data = out.p = buffer;
559 			out.size = sizeof(buffer);
560 			status = disk_query_volume_information(This, file, info_level, &out);
561 			result = buffer_len = out.p - out.data;
562 			break;
563 
564 		case IRP_MJ_DIRECTORY_CONTROL:
565 
566 			if (This->rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
567 			{
568 				status = STATUS_INVALID_HANDLE;
569 				break;
570 			}
571 
572 			switch (minor)
573 			{
574 				case IRP_MN_QUERY_DIRECTORY:
575 
576 					in_uint32_le(s, info_level);
577 					in_uint8s(s, 1);
578 					in_uint32_le(s, length);
579 					in_uint8s(s, 0x17);
580 					if (length && length < 2 * 255)
581 					{
582 						rdp_in_unistr(This, s, filename, length);
583 						convert_to_unix_filename(filename);
584 					}
585 					else
586 					{
587 						filename[0] = 0;
588 					}
589 					out.data = out.p = buffer;
590 					out.size = sizeof(buffer);
591 					status = disk_query_directory(This, file, info_level, filename,
592 								      &out);
593 					result = buffer_len = out.p - out.data;
594 					if (!buffer_len)
595 						buffer_len++;
596 					break;
597 
598 				case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
599 
600 					/* JIF
601 					   unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor);  */
602 
603 					in_uint32_le(s, info_level);	/* notify mask */
604 
605 					This->notify_stamp = True;
606 
607 					status = disk_create_notify(This, file, info_level);
608 					result = 0;
609 
610 					if (status == STATUS_PENDING)
611 						add_async_iorequest(This, device, file, id, major, length,
612 								    fns, 0, 0, NULL, 0);
613 					break;
614 
615 				default:
616 
617 					status = STATUS_INVALID_PARAMETER;
618 					/* JIF */
619 					unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
620 			}
621 			break;
622 
623 		case IRP_MJ_DEVICE_CONTROL:
624 
625 			if (!fns->device_control)
626 			{
627 				status = STATUS_NOT_SUPPORTED;
628 				break;
629 			}
630 
631 			in_uint32_le(s, bytes_out);
632 			in_uint32_le(s, bytes_in);
633 			in_uint32_le(s, request);
634 			in_uint8s(s, 0x14);
635 
636 			buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14);
637 			if (!buffer)
638 			{
639 				status = STATUS_CANCELLED;
640 				break;
641 			}
642 
643 			out.data = out.p = buffer;
644 			out.size = sizeof(buffer);
645 			status = fns->device_control(This, file, request, s, &out);
646 			result = buffer_len = out.p - out.data;
647 
648 			/* Serial SERIAL_WAIT_ON_MASK */
649 			if (status == STATUS_PENDING)
650 			{
651 				if (add_async_iorequest
652 				    (This, device, file, id, major, length, fns, 0, 0, NULL, 0))
653 				{
654 					status = STATUS_PENDING;
655 					break;
656 				}
657 			}
658 			break;
659 
660 
661 		case IRP_MJ_LOCK_CONTROL:
662 
663 			if (This->rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
664 			{
665 				status = STATUS_INVALID_HANDLE;
666 				break;
667 			}
668 
669 			in_uint32_le(s, info_level);
670 
671 			out.data = out.p = buffer;
672 			out.size = sizeof(buffer);
673 			/* FIXME: Perhaps consider actually *do*
674 			   something here :-) */
675 			status = STATUS_SUCCESS;
676 			result = buffer_len = out.p - out.data;
677 			break;
678 
679 		default:
680 			unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
681 			break;
682 	}
683 
684 	if (status != STATUS_PENDING)
685 	{
686 		rdpdr_send_completion(This, device, id, status, result, buffer, buffer_len);
687 	}
688 	if (buffer)
689 		xfree(buffer);
690 	buffer = NULL;
691 }
692 
693 static void
rdpdr_send_clientcapabilty(RDPCLIENT * This)694 rdpdr_send_clientcapabilty(RDPCLIENT * This)
695 {
696 	uint8 magic[4] = "rDPC";
697 	STREAM s;
698 
699 	s = channel_init(This, This->rdpdr.channel, 0x50);
700 	out_uint8a(s, magic, 4);
701 	out_uint32_le(s, 5);	/* count */
702 	out_uint16_le(s, 1);	/* first */
703 	out_uint16_le(s, 0x28);	/* length */
704 	out_uint32_le(s, 1);
705 	out_uint32_le(s, 2);
706 	out_uint16_le(s, 2);
707 	out_uint16_le(s, 5);
708 	out_uint16_le(s, 1);
709 	out_uint16_le(s, 5);
710 	out_uint16_le(s, 0xFFFF);
711 	out_uint16_le(s, 0);
712 	out_uint32_le(s, 0);
713 	out_uint32_le(s, 3);
714 	out_uint32_le(s, 0);
715 	out_uint32_le(s, 0);
716 	out_uint16_le(s, 2);	/* second */
717 	out_uint16_le(s, 8);	/* length */
718 	out_uint32_le(s, 1);
719 	out_uint16_le(s, 3);	/* third */
720 	out_uint16_le(s, 8);	/* length */
721 	out_uint32_le(s, 1);
722 	out_uint16_le(s, 4);	/* fourth */
723 	out_uint16_le(s, 8);	/* length */
724 	out_uint32_le(s, 1);
725 	out_uint16_le(s, 5);	/* fifth */
726 	out_uint16_le(s, 8);	/* length */
727 	out_uint32_le(s, 1);
728 
729 	s_mark_end(s);
730 	channel_send(This, s, This->rdpdr.channel);
731 }
732 
733 static void
rdpdr_process(RDPCLIENT * This,STREAM s)734 rdpdr_process(RDPCLIENT * This, STREAM s)
735 {
736 	uint32 handle;
737 	uint8 *magic;
738 
739 #if WITH_DEBUG_RDP5
740 	printf("--- rdpdr_process ---\n");
741 	hexdump(s->p, s->end - s->p);
742 #endif
743 	in_uint8p(s, magic, 4);
744 
745 	if ((magic[0] == 'r') && (magic[1] == 'D'))
746 	{
747 		if ((magic[2] == 'R') && (magic[3] == 'I'))
748 		{
749 			rdpdr_process_irp(This, s);
750 			return;
751 		}
752 		if ((magic[2] == 'n') && (magic[3] == 'I'))
753 		{
754 			rdpdr_send_connect(This);
755 			rdpdr_send_name(This);
756 			return;
757 		}
758 		if ((magic[2] == 'C') && (magic[3] == 'C'))
759 		{
760 			/* connect from server */
761 			rdpdr_send_clientcapabilty(This);
762 			rdpdr_send_available(This);
763 			return;
764 		}
765 		if ((magic[2] == 'r') && (magic[3] == 'd'))
766 		{
767 			/* connect to a specific resource */
768 			in_uint32(s, handle);
769 #if WITH_DEBUG_RDP5
770 			DEBUG(("RDPDR: Server connected to resource %d\n", handle));
771 #endif
772 			return;
773 		}
774 		if ((magic[2] == 'P') && (magic[3] == 'S'))
775 		{
776 			/* server capability */
777 			return;
778 		}
779 	}
780 	if ((magic[0] == 'R') && (magic[1] == 'P'))
781 	{
782 		if ((magic[2] == 'C') && (magic[3] == 'P'))
783 		{
784 			printercache_process(This, s);
785 			return;
786 		}
787 	}
788 	unimpl("RDPDR packet type %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]);
789 }
790 
791 BOOL
rdpdr_init(RDPCLIENT * This)792 rdpdr_init(RDPCLIENT * This)
793 {
794 	if (This->num_devices > 0)
795 	{
796 		This->rdpdr.channel =
797 			channel_register(This, "rdpdr",
798 					 CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP,
799 					 rdpdr_process);
800 	}
801 
802 	return (This->rdpdr.channel != NULL);
803 }
804 
805 /* Add file descriptors of pending io request to select() */
806 void
rdpdr_add_fds(RDPCLIENT * This,int * n,fd_set * rfds,fd_set * wfds,struct timeval * tv,BOOL * timeout)807 rdpdr_add_fds(RDPCLIENT * This, int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * timeout)
808 {
809 	uint32 select_timeout = 0;	/* Timeout value to be used for select() (in millisecons). */
810 	struct async_iorequest *iorq;
811 	char c;
812 
813 	iorq = This->iorequest;
814 	while (iorq != NULL)
815 	{
816 		if (iorq->fd != 0)
817 		{
818 			switch (iorq->major)
819 			{
820 				case IRP_MJ_READ:
821 					/* Is this FD valid? FDs will
822 					   be invalid when
823 					   reconnecting. FIXME: Real
824 					   support for reconnects. */
825 
826 					FD_SET(iorq->fd, rfds);
827 					*n = MAX(*n, iorq->fd);
828 
829 					/* Check if io request timeout is smaller than current (but not 0). */
830 					if (iorq->timeout
831 					    && (select_timeout == 0
832 						|| iorq->timeout < select_timeout))
833 					{
834 						/* Set new timeout */
835 						select_timeout = iorq->timeout;
836 						This->min_timeout_fd = iorq->fd;	/* Remember fd */
837 						tv->tv_sec = select_timeout / 1000;
838 						tv->tv_usec = (select_timeout % 1000) * 1000;
839 						*timeout = True;
840 						break;
841 					}
842 					if (iorq->itv_timeout && iorq->partial_len > 0
843 					    && (select_timeout == 0
844 						|| iorq->itv_timeout < select_timeout))
845 					{
846 						/* Set new timeout */
847 						select_timeout = iorq->itv_timeout;
848 						This->min_timeout_fd = iorq->fd;	/* Remember fd */
849 						tv->tv_sec = select_timeout / 1000;
850 						tv->tv_usec = (select_timeout % 1000) * 1000;
851 						*timeout = True;
852 						break;
853 					}
854 					break;
855 
856 				case IRP_MJ_WRITE:
857 					/* FD still valid? See above. */
858 					if ((write(iorq->fd, &c, 0) != 0) && (errno == EBADF))
859 						break;
860 
861 					FD_SET(iorq->fd, wfds);
862 					*n = MAX(*n, iorq->fd);
863 					break;
864 
865 				case IRP_MJ_DEVICE_CONTROL:
866 					if (select_timeout > 5)
867 						select_timeout = 5;	/* serial event queue */
868 					break;
869 
870 			}
871 
872 		}
873 
874 		iorq = iorq->next;
875 	}
876 }
877 
878 struct async_iorequest *
rdpdr_remove_iorequest(RDPCLIENT * This,struct async_iorequest * prev,struct async_iorequest * iorq)879 rdpdr_remove_iorequest(RDPCLIENT * This, struct async_iorequest *prev, struct async_iorequest *iorq)
880 {
881 	if (!iorq)
882 		return NULL;
883 
884 	if (iorq->buffer)
885 		xfree(iorq->buffer);
886 	if (prev)
887 	{
888 		prev->next = iorq->next;
889 		xfree(iorq);
890 		iorq = prev->next;
891 	}
892 	else
893 	{
894 		/* Even if NULL */
895 		This->iorequest = iorq->next;
896 		xfree(iorq);
897 		iorq = NULL;
898 	}
899 	return iorq;
900 }
901 
902 /* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
903 static void
_rdpdr_check_fds(RDPCLIENT * This,fd_set * rfds,fd_set * wfds,BOOL timed_out)904 _rdpdr_check_fds(RDPCLIENT * This, fd_set * rfds, fd_set * wfds, BOOL timed_out)
905 {
906 	NTSTATUS status;
907 	uint32 result = 0;
908 	DEVICE_FNS *fns;
909 	struct async_iorequest *iorq;
910 	struct async_iorequest *prev;
911 	uint32 req_size = 0;
912 	uint32 buffer_len;
913 	struct stream out;
914 	uint8 *buffer = NULL;
915 
916 
917 	if (timed_out)
918 	{
919 		/* check serial iv_timeout */
920 
921 		iorq = This->iorequest;
922 		prev = NULL;
923 		while (iorq != NULL)
924 		{
925 			if (iorq->fd == This->min_timeout_fd)
926 			{
927 				if ((iorq->partial_len > 0) &&
928 				    (This->rdpdr_device[iorq->device].device_type ==
929 				     DEVICE_TYPE_SERIAL))
930 				{
931 
932 					/* iv_timeout between 2 chars, send partial_len */
933 					/*printf("RDPDR: IVT total %u bytes read of %u\n", iorq->partial_len, iorq->length); */
934 					rdpdr_send_completion(This, iorq->device,
935 							      iorq->id, STATUS_SUCCESS,
936 							      iorq->partial_len,
937 							      iorq->buffer, iorq->partial_len);
938 					iorq = rdpdr_remove_iorequest(This, prev, iorq);
939 					return;
940 				}
941 				else
942 				{
943 					break;
944 				}
945 
946 			}
947 			else
948 			{
949 				break;
950 			}
951 
952 
953 			prev = iorq;
954 			if (iorq)
955 				iorq = iorq->next;
956 
957 		}
958 
959 		rdpdr_abort_io(This, This->min_timeout_fd, 0, STATUS_TIMEOUT);
960 		return;
961 	}
962 
963 	iorq = This->iorequest;
964 	prev = NULL;
965 	while (iorq != NULL)
966 	{
967 		if (iorq->fd != 0)
968 		{
969 			switch (iorq->major)
970 			{
971 				case IRP_MJ_READ:
972 					if (FD_ISSET(iorq->fd, rfds))
973 					{
974 						/* Read the data */
975 						fns = iorq->fns;
976 
977 						req_size =
978 							(iorq->length - iorq->partial_len) >
979 							8192 ? 8192 : (iorq->length -
980 								       iorq->partial_len);
981 						/* never read larger chunks than 8k - chances are that it will block */
982 						status = fns->read(This, iorq->fd,
983 								   iorq->buffer + iorq->partial_len,
984 								   req_size, iorq->offset, &result);
985 
986 						if ((long) result > 0)
987 						{
988 							iorq->partial_len += result;
989 							iorq->offset += result;
990 						}
991 #if WITH_DEBUG_RDP5
992 						DEBUG(("RDPDR: %d bytes of data read\n", result));
993 #endif
994 						/* only delete link if all data has been transfered */
995 						/* or if result was 0 and status success - EOF      */
996 						if ((iorq->partial_len == iorq->length) ||
997 						    (result == 0))
998 						{
999 #if WITH_DEBUG_RDP5
1000 							DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length));
1001 #endif
1002 							rdpdr_send_completion(This, iorq->device,
1003 									      iorq->id, status,
1004 									      iorq->partial_len,
1005 									      iorq->buffer,
1006 									      iorq->partial_len);
1007 							iorq = rdpdr_remove_iorequest(This, prev, iorq);
1008 						}
1009 					}
1010 					break;
1011 				case IRP_MJ_WRITE:
1012 					if (FD_ISSET(iorq->fd, wfds))
1013 					{
1014 						/* Write data. */
1015 						fns = iorq->fns;
1016 
1017 						req_size =
1018 							(iorq->length - iorq->partial_len) >
1019 							8192 ? 8192 : (iorq->length -
1020 								       iorq->partial_len);
1021 
1022 						/* never write larger chunks than 8k - chances are that it will block */
1023 						status = fns->write(This, iorq->fd,
1024 								    iorq->buffer +
1025 								    iorq->partial_len, req_size,
1026 								    iorq->offset, &result);
1027 
1028 						if ((long) result > 0)
1029 						{
1030 							iorq->partial_len += result;
1031 							iorq->offset += result;
1032 						}
1033 
1034 #if WITH_DEBUG_RDP5
1035 						DEBUG(("RDPDR: %d bytes of data written\n",
1036 						       result));
1037 #endif
1038 						/* only delete link if all data has been transfered */
1039 						/* or we couldn't write */
1040 						if ((iorq->partial_len == iorq->length)
1041 						    || (result == 0))
1042 						{
1043 #if WITH_DEBUG_RDP5
1044 							DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length));
1045 #endif
1046 							rdpdr_send_completion(This, iorq->device,
1047 									      iorq->id, status,
1048 									      iorq->partial_len,
1049 									      (uint8 *) "", 1);
1050 
1051 							iorq = rdpdr_remove_iorequest(This, prev, iorq);
1052 						}
1053 					}
1054 					break;
1055 				case IRP_MJ_DEVICE_CONTROL:
1056 					if (serial_get_event(This, iorq->fd, &result))
1057 					{
1058 						buffer = (uint8 *) xrealloc((void *) buffer, 0x14);
1059 						out.data = out.p = buffer;
1060 						out.size = sizeof(buffer);
1061 						out_uint32_le(&out, result);
1062 						result = buffer_len = out.p - out.data;
1063 						status = STATUS_SUCCESS;
1064 						rdpdr_send_completion(This, iorq->device, iorq->id,
1065 								      status, result, buffer,
1066 								      buffer_len);
1067 						xfree(buffer);
1068 						iorq = rdpdr_remove_iorequest(This, prev, iorq);
1069 					}
1070 
1071 					break;
1072 			}
1073 
1074 		}
1075 		prev = iorq;
1076 		if (iorq)
1077 			iorq = iorq->next;
1078 	}
1079 
1080 	/* Check notify */
1081 	iorq = This->iorequest;
1082 	prev = NULL;
1083 	while (iorq != NULL)
1084 	{
1085 		if (iorq->fd != 0)
1086 		{
1087 			switch (iorq->major)
1088 			{
1089 
1090 				case IRP_MJ_DIRECTORY_CONTROL:
1091 					if (This->rdpdr_device[iorq->device].device_type ==
1092 					    DEVICE_TYPE_DISK)
1093 					{
1094 
1095 						if (This->notify_stamp)
1096 						{
1097 							This->notify_stamp = False;
1098 							status = disk_check_notify(This, iorq->fd);
1099 							if (status != STATUS_PENDING)
1100 							{
1101 								rdpdr_send_completion(This, iorq->device,
1102 										      iorq->id,
1103 										      status, 0,
1104 										      NULL, 0);
1105 								iorq = rdpdr_remove_iorequest(This, prev,
1106 											      iorq);
1107 							}
1108 						}
1109 					}
1110 					break;
1111 
1112 
1113 
1114 			}
1115 		}
1116 
1117 		prev = iorq;
1118 		if (iorq)
1119 			iorq = iorq->next;
1120 	}
1121 
1122 }
1123 
1124 void
rdpdr_check_fds(RDPCLIENT * This,fd_set * rfds,fd_set * wfds,BOOL timed_out)1125 rdpdr_check_fds(RDPCLIENT * This, fd_set * rfds, fd_set * wfds, BOOL timed_out)
1126 {
1127 	fd_set dummy;
1128 
1129 
1130 	FD_ZERO(&dummy);
1131 
1132 
1133 	/* fist check event queue only,
1134 	   any serial wait event must be done before read block will be sent
1135 	 */
1136 
1137 	_rdpdr_check_fds(This, &dummy, &dummy, False);
1138 	_rdpdr_check_fds(This, rfds, wfds, timed_out);
1139 }
1140 
1141 
1142 /* Abort a pending io request for a given handle and major */
1143 BOOL
rdpdr_abort_io(RDPCLIENT * This,uint32 fd,uint32 major,NTSTATUS status)1144 rdpdr_abort_io(RDPCLIENT * This, uint32 fd, uint32 major, NTSTATUS status)
1145 {
1146 	uint32 result;
1147 	struct async_iorequest *iorq;
1148 	struct async_iorequest *prev;
1149 
1150 	iorq = This->iorequest;
1151 	prev = NULL;
1152 	while (iorq != NULL)
1153 	{
1154 		/* Only remove from table when major is not set, or when correct major is supplied.
1155 		   Abort read should not abort a write io request. */
1156 		if ((iorq->fd == fd) && (major == 0 || iorq->major == major))
1157 		{
1158 			result = 0;
1159 			rdpdr_send_completion(This, iorq->device, iorq->id, status, result, (uint8 *) "",
1160 					      1);
1161 
1162 			iorq = rdpdr_remove_iorequest(This, prev, iorq);
1163 			return True;
1164 		}
1165 
1166 		prev = iorq;
1167 		iorq = iorq->next;
1168 	}
1169 
1170 	return False;
1171 }
1172