/[rdesktop]/sourceforge.net/trunk/rdesktop/rdpdr.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /sourceforge.net/trunk/rdesktop/rdpdr.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 657 - (hide annotations)
Fri Apr 16 11:28:34 2004 UTC (20 years, 1 month ago) by astrand
File MIME type: text/plain
File size: 22454 byte(s)
Added copyright header and links to IRP resources.

1 astrand 657 /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.
3     Copyright (C) Matthew Chapman 1999-2004
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
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 stargo 570 #include <unistd.h>
37 stargo 576 #include <sys/types.h>
38 stargo 609 #include <sys/time.h>
39 n-ki 627 #include <dirent.h> /* opendir, closedir, readdir */
40 stargo 576 #include <time.h>
41 matthewc 432 #include "rdesktop.h"
42    
43 n-ki 569 #define IRP_MJ_CREATE 0x00
44     #define IRP_MJ_CLOSE 0x02
45     #define IRP_MJ_READ 0x03
46     #define IRP_MJ_WRITE 0x04
47     #define IRP_MJ_QUERY_INFORMATION 0x05
48     #define IRP_MJ_SET_INFORMATION 0x06
49     #define IRP_MJ_QUERY_VOLUME_INFORMATION 0x0a
50     #define IRP_MJ_DIRECTORY_CONTROL 0x0c
51     #define IRP_MJ_DEVICE_CONTROL 0x0e
52 astrand 650 #define IRP_MJ_LOCK_CONTROL 0x11
53 n-ki 569
54     #define IRP_MN_QUERY_DIRECTORY 0x01
55     #define IRP_MN_NOTIFY_CHANGE_DIRECTORY 0x02
56    
57 matthewc 432 extern char hostname[16];
58     extern DEVICE_FNS serial_fns;
59     extern DEVICE_FNS printer_fns;
60 n-ki 569 extern DEVICE_FNS parallel_fns;
61     extern DEVICE_FNS disk_fns;
62 n-ki 627 extern FILEINFO g_fileinfo[];
63 matthewc 432
64     static VCHANNEL *rdpdr_channel;
65    
66 n-ki 569 /* If select() times out, the request for the device with handle g_min_timeout_fd is aborted */
67     HANDLE g_min_timeout_fd;
68     uint32 g_num_devices;
69    
70     /* Table with information about rdpdr devices */
71     RDPDR_DEVICE g_rdpdr_device[RDPDR_MAX_DEVICES];
72 astrand 651 char *g_rdpdr_clientname = NULL;
73 n-ki 569
74     /* Used to store incoming io request, until they are ready to be completed */
75 n-ki 592 /* using a linked list ensures that they are processed in the right order, */
76     /* if multiple ios are being done on the same fd */
77 n-ki 569 struct async_iorequest
78     {
79 n-ki 592 uint32 fd, major, minor, offset, device, id, length, partial_len;
80 n-ki 569 long timeout, /* Total timeout */
81     itv_timeout; /* Interval timeout (between serial characters) */
82     uint8 *buffer;
83     DEVICE_FNS *fns;
84    
85 n-ki 592 struct async_iorequest *next; /* next element in list */
86 n-ki 593 };
87 n-ki 592
88 n-ki 593 struct async_iorequest *g_iorequest;
89    
90 n-ki 569 /* Return device_id for a given handle */
91     int
92     get_device_index(HANDLE handle)
93     {
94     int i;
95     for (i = 0; i < RDPDR_MAX_DEVICES; i++)
96     {
97     if (g_rdpdr_device[i].handle == handle)
98     return i;
99     }
100     return -1;
101     }
102    
103     /* Converts a windows path to a unix path */
104 matthewc 432 void
105 n-ki 569 convert_to_unix_filename(char *filename)
106     {
107     char *p;
108    
109     while ((p = strchr(filename, '\\')))
110     {
111     *p = '/';
112     }
113     }
114    
115 n-ki 627 BOOL
116     rdpdr_handle_ok(int device, int handle)
117     {
118     switch (g_rdpdr_device[device].device_type)
119     {
120     case DEVICE_TYPE_PARALLEL:
121     case DEVICE_TYPE_SERIAL:
122     case DEVICE_TYPE_PRINTER:
123     case DEVICE_TYPE_SCARD:
124     if (g_rdpdr_device[device].handle != handle)
125     return False;
126     break;
127     case DEVICE_TYPE_DISK:
128     if (g_fileinfo[handle].device_id != device)
129     return False;
130     break;
131     }
132     return True;
133     }
134    
135 n-ki 569 /* Add a new io request to the table containing pending io requests so it won't block rdesktop */
136     BOOL
137     add_async_iorequest(uint32 device, uint32 file, uint32 id, uint32 major, uint32 length,
138 n-ki 613 DEVICE_FNS * fns, uint32 total_timeout, uint32 interval_timeout, uint8 * buffer,
139     uint32 offset)
140 n-ki 569 {
141     struct async_iorequest *iorq;
142    
143 n-ki 593 if (g_iorequest == NULL)
144     {
145     g_iorequest = (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
146 n-ki 612 if (!g_iorequest)
147     return False;
148 n-ki 593 g_iorequest->fd = 0;
149     g_iorequest->next = NULL;
150     }
151    
152     iorq = g_iorequest;
153    
154 n-ki 592 while (iorq->fd != 0)
155 n-ki 569 {
156 n-ki 592 // create new element if needed
157     if (iorq->next == NULL)
158 n-ki 569 {
159 n-ki 592 iorq->next =
160     (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
161 n-ki 612 if (!iorq->next)
162     return False;
163 n-ki 593 iorq->next->fd = 0;
164     iorq->next->next = NULL;
165 n-ki 592 }
166 n-ki 593 iorq = iorq->next;
167 n-ki 569 }
168 n-ki 592 iorq->device = device;
169     iorq->fd = file;
170     iorq->id = id;
171     iorq->major = major;
172     iorq->length = length;
173     iorq->partial_len = 0;
174     iorq->fns = fns;
175     iorq->timeout = total_timeout;
176     iorq->itv_timeout = interval_timeout;
177     iorq->buffer = buffer;
178 n-ki 613 iorq->offset = offset;
179 n-ki 592 return True;
180 n-ki 569 }
181    
182     void
183 matthewc 432 rdpdr_send_connect(void)
184     {
185     uint8 magic[4] = "rDCC";
186     STREAM s;
187    
188     s = channel_init(rdpdr_channel, 12);
189     out_uint8a(s, magic, 4);
190 astrand 435 out_uint16_le(s, 1); /* unknown */
191 matthewc 432 out_uint16_le(s, 5);
192 astrand 435 out_uint32_be(s, 0x815ed39d); /* IP address (use 127.0.0.1) 0x815ed39d */
193 matthewc 432 s_mark_end(s);
194     channel_send(s, rdpdr_channel);
195     }
196    
197 n-ki 569
198 matthewc 432 void
199     rdpdr_send_name(void)
200     {
201     uint8 magic[4] = "rDNC";
202 astrand 647 STREAM s;
203     uint32 hostlen;
204    
205 astrand 651 if (NULL == g_rdpdr_clientname)
206     {
207     g_rdpdr_clientname = hostname;
208 forsberg 646 }
209 astrand 647 hostlen = (strlen(g_rdpdr_clientname) + 1) * 2;
210 matthewc 432
211 astrand 435 s = channel_init(rdpdr_channel, 16 + hostlen);
212 matthewc 432 out_uint8a(s, magic, 4);
213 astrand 435 out_uint16_le(s, 0x63); /* unknown */
214 matthewc 432 out_uint16_le(s, 0x72);
215     out_uint32(s, 0);
216     out_uint32_le(s, hostlen);
217 forsberg 646 rdp_out_unistr(s, g_rdpdr_clientname, hostlen - 2);
218 matthewc 432 s_mark_end(s);
219     channel_send(s, rdpdr_channel);
220     }
221    
222 n-ki 569 /* Returns the size of the payload of the announce packet */
223     int
224     announcedata_size()
225     {
226     int size, i;
227     PRINTER *printerinfo;
228    
229     size = 8; //static announce size
230     size += g_num_devices * 0x14;
231    
232     for (i = 0; i < g_num_devices; i++)
233     {
234     if (g_rdpdr_device[i].device_type == DEVICE_TYPE_PRINTER)
235     {
236     printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
237     printerinfo->bloblen =
238     printercache_load_blob(printerinfo->printer, &(printerinfo->blob));
239    
240     size += 0x18;
241     size += 2 * strlen(printerinfo->driver) + 2;
242     size += 2 * strlen(printerinfo->printer) + 2;
243     size += printerinfo->bloblen;
244     }
245     }
246    
247     return size;
248     }
249    
250 matthewc 432 void
251     rdpdr_send_available(void)
252     {
253 n-ki 569
254 matthewc 432 uint8 magic[4] = "rDAD";
255 n-ki 569 uint32 driverlen, printerlen, bloblen;
256     int i;
257 matthewc 432 STREAM s;
258 n-ki 569 PRINTER *printerinfo;
259 matthewc 432
260 n-ki 569 s = channel_init(rdpdr_channel, announcedata_size());
261 matthewc 432 out_uint8a(s, magic, 4);
262 n-ki 569 out_uint32_le(s, g_num_devices);
263 matthewc 432
264 n-ki 569 for (i = 0; i < g_num_devices; i++)
265     {
266     out_uint32_le(s, g_rdpdr_device[i].device_type);
267     out_uint32_le(s, i); /* RDP Device ID */
268     out_uint8p(s, g_rdpdr_device[i].name, 8);
269    
270 n-ki 585 switch (g_rdpdr_device[i].device_type)
271 n-ki 569 {
272 n-ki 585 case DEVICE_TYPE_PRINTER:
273     printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
274 n-ki 569
275 n-ki 585 driverlen = 2 * strlen(printerinfo->driver) + 2;
276     printerlen = 2 * strlen(printerinfo->printer) + 2;
277     bloblen = printerinfo->bloblen;
278 n-ki 569
279 n-ki 585 out_uint32_le(s, 24 + driverlen + printerlen + bloblen); /* length of extra info */
280     out_uint32_le(s, printerinfo->default_printer ? 2 : 0);
281     out_uint8s(s, 8); /* unknown */
282     out_uint32_le(s, driverlen);
283     out_uint32_le(s, printerlen);
284     out_uint32_le(s, bloblen);
285     rdp_out_unistr(s, printerinfo->driver, driverlen - 2);
286     rdp_out_unistr(s, printerinfo->printer, printerlen - 2);
287     out_uint8a(s, printerinfo->blob, bloblen);
288 n-ki 569
289 n-ki 598 if (printerinfo->blob)
290     xfree(printerinfo->blob); /* Blob is sent twice if reconnecting */
291 n-ki 585 break;
292     default:
293     out_uint32(s, 0);
294 n-ki 569 }
295     }
296 matthewc 432 #if 0
297 astrand 435 out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */
298 matthewc 432 out_uint32_le(s, 0);
299     out_uint8p(s, "SCARD", 5);
300     out_uint8s(s, 3);
301     out_uint32(s, 0);
302     #endif
303    
304     s_mark_end(s);
305     channel_send(s, rdpdr_channel);
306     }
307    
308     void
309 astrand 435 rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
310     uint32 length)
311 matthewc 432 {
312     uint8 magic[4] = "rDCI";
313     STREAM s;
314    
315     s = channel_init(rdpdr_channel, 20 + length);
316     out_uint8a(s, magic, 4);
317     out_uint32_le(s, device);
318     out_uint32_le(s, id);
319     out_uint32_le(s, status);
320     out_uint32_le(s, result);
321     out_uint8p(s, buffer, length);
322     s_mark_end(s);
323 n-ki 569 /* JIF
324     hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
325 matthewc 432 channel_send(s, rdpdr_channel);
326     }
327    
328     static void
329     rdpdr_process_irp(STREAM s)
330     {
331 n-ki 569 uint32 result = 0,
332     length = 0,
333     desired_access = 0,
334     request,
335     file,
336     info_level,
337     buffer_len,
338     id,
339     major,
340     minor,
341     device,
342     offset,
343     bytes_in,
344     bytes_out,
345     error_mode,
346     share_mode, disposition, total_timeout, interval_timeout, flags_and_attributes = 0;
347    
348     char filename[256];
349     uint8 *buffer, *pst_buf;
350 matthewc 432 struct stream out;
351     DEVICE_FNS *fns;
352 n-ki 569 BOOL rw_blocking = True;
353     NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
354 matthewc 432
355     in_uint32_le(s, device);
356     in_uint32_le(s, file);
357     in_uint32_le(s, id);
358     in_uint32_le(s, major);
359     in_uint32_le(s, minor);
360    
361 n-ki 569 buffer_len = 0;
362     buffer = (uint8 *) xmalloc(1024);
363     buffer[0] = 0;
364 matthewc 432
365 n-ki 569 switch (g_rdpdr_device[device].device_type)
366 matthewc 432 {
367 n-ki 569 case DEVICE_TYPE_SERIAL:
368    
369 matthewc 432 fns = &serial_fns;
370 n-ki 592 rw_blocking = False;
371 n-ki 569 break;
372    
373     case DEVICE_TYPE_PARALLEL:
374    
375     fns = &parallel_fns;
376 n-ki 592 rw_blocking = False;
377 n-ki 569 break;
378    
379     case DEVICE_TYPE_PRINTER:
380    
381 matthewc 432 fns = &printer_fns;
382 n-ki 569 break;
383    
384     case DEVICE_TYPE_DISK:
385    
386 n-ki 593 fns = &disk_fns;
387 n-ki 595 rw_blocking = False;
388 n-ki 569 break;
389    
390     case DEVICE_TYPE_SCARD:
391 matthewc 432 default:
392 n-ki 569
393 matthewc 432 error("IRP for bad device %ld\n", device);
394     return;
395     }
396    
397     switch (major)
398     {
399     case IRP_MJ_CREATE:
400 n-ki 569
401     in_uint32_be(s, desired_access);
402     in_uint8s(s, 0x08); // unknown
403     in_uint32_le(s, error_mode);
404     in_uint32_le(s, share_mode);
405     in_uint32_le(s, disposition);
406     in_uint32_le(s, flags_and_attributes);
407     in_uint32_le(s, length);
408    
409     if (length && (length / 2) < 256)
410     {
411     rdp_in_unistr(s, filename, length);
412     convert_to_unix_filename(filename);
413     }
414     else
415     {
416     filename[0] = 0;
417     }
418    
419     if (!fns->create)
420     {
421     status = STATUS_NOT_SUPPORTED;
422     break;
423     }
424    
425     status = fns->create(device, desired_access, share_mode, disposition,
426     flags_and_attributes, filename, &result);
427     buffer_len = 1;
428 matthewc 432 break;
429    
430     case IRP_MJ_CLOSE:
431 n-ki 569 if (!fns->close)
432     {
433     status = STATUS_NOT_SUPPORTED;
434     break;
435     }
436    
437     status = fns->close(file);
438 matthewc 432 break;
439    
440     case IRP_MJ_READ:
441 n-ki 569
442     if (!fns->read)
443 matthewc 432 {
444 n-ki 569 status = STATUS_NOT_SUPPORTED;
445     break;
446     }
447    
448     in_uint32_le(s, length);
449     in_uint32_le(s, offset);
450     #if WITH_DEBUG_RDP5
451     DEBUG(("RDPDR IRP Read (length: %d, offset: %d)\n", length, offset));
452     #endif
453 n-ki 627 if (!rdpdr_handle_ok(device, file))
454     {
455     status = STATUS_INVALID_HANDLE;
456     break;
457     }
458    
459 n-ki 592 if (rw_blocking) // Complete read immediately
460     {
461 n-ki 569 buffer = (uint8 *) xrealloc((void *) buffer, length);
462 n-ki 612 if (!buffer)
463     {
464     status = STATUS_CANCELLED;
465     break;
466     }
467 n-ki 569 status = fns->read(file, buffer, length, offset, &result);
468 matthewc 432 buffer_len = result;
469 n-ki 569 break;
470 n-ki 592 }
471 n-ki 569
472     // Add request to table
473     pst_buf = (uint8 *) xmalloc(length);
474 n-ki 612 if (!pst_buf)
475     {
476     status = STATUS_CANCELLED;
477     break;
478     }
479 n-ki 569 serial_get_timeout(file, length, &total_timeout, &interval_timeout);
480     if (add_async_iorequest
481     (device, file, id, major, length, fns, total_timeout, interval_timeout,
482 n-ki 613 pst_buf, offset))
483 n-ki 569 {
484     status = STATUS_PENDING;
485     break;
486     }
487    
488     status = STATUS_CANCELLED;
489 matthewc 432 break;
490     case IRP_MJ_WRITE:
491 n-ki 569
492     buffer_len = 1;
493    
494     if (!fns->write)
495     {
496     status = STATUS_NOT_SUPPORTED;
497     break;
498     }
499    
500     in_uint32_le(s, length);
501     in_uint32_le(s, offset);
502     in_uint8s(s, 0x18);
503     #if WITH_DEBUG_RDP5
504     DEBUG(("RDPDR IRP Write (length: %d)\n", result));
505     #endif
506 n-ki 627 if (!rdpdr_handle_ok(device, file))
507     {
508     status = STATUS_INVALID_HANDLE;
509     break;
510     }
511    
512 n-ki 592 if (rw_blocking) // Complete immediately
513     {
514 n-ki 569 status = fns->write(file, s->p, length, offset, &result);
515     break;
516 n-ki 592 }
517    
518 n-ki 569 // Add to table
519     pst_buf = (uint8 *) xmalloc(length);
520 n-ki 612 if (!pst_buf)
521     {
522     status = STATUS_CANCELLED;
523     break;
524     }
525    
526 n-ki 569 in_uint8a(s, pst_buf, length);
527    
528     if (add_async_iorequest
529 n-ki 613 (device, file, id, major, length, fns, 0, 0, pst_buf, offset))
530 n-ki 569 {
531     status = STATUS_PENDING;
532     break;
533     }
534    
535     status = STATUS_CANCELLED;
536 matthewc 432 break;
537    
538 n-ki 569 case IRP_MJ_QUERY_INFORMATION:
539    
540     if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
541     {
542     status = STATUS_INVALID_HANDLE;
543     break;
544     }
545     in_uint32_le(s, info_level);
546    
547     out.data = out.p = buffer;
548     out.size = sizeof(buffer);
549     status = disk_query_information(file, info_level, &out);
550     result = buffer_len = out.p - out.data;
551    
552     break;
553    
554     case IRP_MJ_SET_INFORMATION:
555    
556     if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
557     {
558     status = STATUS_INVALID_HANDLE;
559     break;
560     }
561    
562     in_uint32_le(s, info_level);
563    
564     out.data = out.p = buffer;
565     out.size = sizeof(buffer);
566     status = disk_set_information(file, info_level, s, &out);
567     result = buffer_len = out.p - out.data;
568     break;
569    
570     case IRP_MJ_QUERY_VOLUME_INFORMATION:
571    
572     if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
573     {
574     status = STATUS_INVALID_HANDLE;
575     break;
576     }
577    
578     in_uint32_le(s, info_level);
579    
580     out.data = out.p = buffer;
581     out.size = sizeof(buffer);
582     status = disk_query_volume_information(file, info_level, &out);
583     result = buffer_len = out.p - out.data;
584     break;
585    
586     case IRP_MJ_DIRECTORY_CONTROL:
587    
588     if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
589     {
590     status = STATUS_INVALID_HANDLE;
591     break;
592     }
593    
594     switch (minor)
595     {
596     case IRP_MN_QUERY_DIRECTORY:
597    
598     in_uint32_le(s, info_level);
599     in_uint8s(s, 1);
600     in_uint32_le(s, length);
601     in_uint8s(s, 0x17);
602     if (length && length < 2 * 255)
603     {
604     rdp_in_unistr(s, filename, length);
605     convert_to_unix_filename(filename);
606     }
607     else
608     {
609     filename[0] = 0;
610     }
611     out.data = out.p = buffer;
612     out.size = sizeof(buffer);
613     status = disk_query_directory(file, info_level, filename,
614     &out);
615     result = buffer_len = out.p - out.data;
616     if (!buffer_len)
617     buffer_len++;
618     break;
619    
620     case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
621    
622     /* JIF
623     unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */
624     status = STATUS_PENDING; // Don't send completion packet
625     break;
626    
627     default:
628    
629     status = STATUS_INVALID_PARAMETER;
630     /* JIF
631     unimpl("IRP major=0x%x minor=0x%x\n", major, minor); */
632     }
633     break;
634    
635 matthewc 432 case IRP_MJ_DEVICE_CONTROL:
636 n-ki 569
637     if (!fns->device_control)
638 matthewc 432 {
639 n-ki 569 status = STATUS_NOT_SUPPORTED;
640     break;
641 matthewc 432 }
642 n-ki 569
643     in_uint32_le(s, bytes_out);
644     in_uint32_le(s, bytes_in);
645     in_uint32_le(s, request);
646     in_uint8s(s, 0x14);
647    
648     buffer = (uint8 *) xrealloc((void *) buffer, bytes_out + 0x14);
649 n-ki 612 if (!buffer)
650     {
651     status = STATUS_CANCELLED;
652     break;
653     }
654    
655 n-ki 569 out.data = out.p = buffer;
656     out.size = sizeof(buffer);
657     status = fns->device_control(file, request, s, &out);
658     result = buffer_len = out.p - out.data;
659 matthewc 432 break;
660    
661     default:
662     unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
663     break;
664     }
665    
666 n-ki 569 if (status != STATUS_PENDING)
667     {
668     rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
669     }
670 n-ki 612 if (buffer)
671     xfree(buffer);
672     buffer = NULL;
673 matthewc 432 }
674    
675 n-ki 569 void
676     rdpdr_send_clientcapabilty(void)
677     {
678     uint8 magic[4] = "rDPC";
679     STREAM s;
680    
681     s = channel_init(rdpdr_channel, 0x50);
682     out_uint8a(s, magic, 4);
683     out_uint32_le(s, 5); /* count */
684     out_uint16_le(s, 1); /* first */
685     out_uint16_le(s, 0x28); /* length */
686     out_uint32_le(s, 1);
687     out_uint32_le(s, 2);
688     out_uint16_le(s, 2);
689     out_uint16_le(s, 5);
690     out_uint16_le(s, 1);
691     out_uint16_le(s, 5);
692     out_uint16_le(s, 0xFFFF);
693     out_uint16_le(s, 0);
694     out_uint32_le(s, 0);
695     out_uint32_le(s, 3);
696     out_uint32_le(s, 0);
697     out_uint32_le(s, 0);
698     out_uint16_le(s, 2); /* second */
699     out_uint16_le(s, 8); /* length */
700     out_uint32_le(s, 1);
701     out_uint16_le(s, 3); /* third */
702     out_uint16_le(s, 8); /* length */
703     out_uint32_le(s, 1);
704     out_uint16_le(s, 4); /* fourth */
705     out_uint16_le(s, 8); /* length */
706     out_uint32_le(s, 1);
707     out_uint16_le(s, 5); /* fifth */
708     out_uint16_le(s, 8); /* length */
709     out_uint32_le(s, 1);
710    
711     s_mark_end(s);
712     channel_send(s, rdpdr_channel);
713     }
714    
715 matthewc 432 static void
716     rdpdr_process(STREAM s)
717     {
718     uint32 handle;
719 matthewc 536 uint8 *magic;
720 matthewc 432
721 n-ki 569 #if WITH_DEBUG_RDP5
722     printf("--- rdpdr_process ---\n");
723 astrand 435 hexdump(s->p, s->end - s->p);
724 n-ki 569 #endif
725 matthewc 432 in_uint8p(s, magic, 4);
726    
727     if ((magic[0] == 'r') && (magic[1] == 'D'))
728     {
729     if ((magic[2] == 'R') && (magic[3] == 'I'))
730     {
731     rdpdr_process_irp(s);
732     return;
733     }
734     if ((magic[2] == 'n') && (magic[3] == 'I'))
735     {
736     rdpdr_send_connect();
737     rdpdr_send_name();
738     return;
739     }
740 n-ki 569 if ((magic[2] == 'C') && (magic[3] == 'C'))
741 matthewc 432 {
742     /* connect from server */
743 n-ki 569 rdpdr_send_clientcapabilty();
744     rdpdr_send_available();
745 matthewc 432 return;
746     }
747 n-ki 569 if ((magic[2] == 'r') && (magic[3] == 'd'))
748 matthewc 432 {
749     /* connect to a specific resource */
750     in_uint32(s, handle);
751 n-ki 569 #if WITH_DEBUG_RDP5
752     DEBUG(("RDPDR: Server connected to resource %d\n", handle));
753     #endif
754 matthewc 432 return;
755     }
756 n-ki 569 if ((magic[2] == 'P') && (magic[3] == 'S'))
757     {
758     /* server capability */
759     return;
760     }
761 matthewc 432 }
762 n-ki 569 if ((magic[0] == 'R') && (magic[1] == 'P'))
763     {
764     if ((magic[2] == 'C') && (magic[3] == 'P'))
765     {
766     printercache_process(s);
767     return;
768     }
769     }
770 matthewc 432 unimpl("RDPDR packet type %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]);
771     }
772    
773     BOOL
774 n-ki 569 rdpdr_init()
775 matthewc 432 {
776 n-ki 569 if (g_num_devices > 0)
777     {
778 astrand 580 rdpdr_channel =
779     channel_register("rdpdr",
780     CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP,
781     rdpdr_process);
782 n-ki 569 }
783    
784 matthewc 432 return (rdpdr_channel != NULL);
785     }
786 n-ki 569
787     /* Add file descriptors of pending io request to select() */
788     void
789     rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * timeout)
790     {
791 stargo 607 uint32 select_timeout = 0; // Timeout value to be used for select() (in millisecons).
792 n-ki 569 struct async_iorequest *iorq;
793    
794 n-ki 593 iorq = g_iorequest;
795 n-ki 592 while (iorq != NULL)
796 n-ki 569 {
797 n-ki 592 if (iorq->fd != 0)
798 n-ki 569 {
799     switch (iorq->major)
800     {
801     case IRP_MJ_READ:
802    
803     FD_SET(iorq->fd, rfds);
804    
805     // Check if io request timeout is smaller than current (but not 0).
806     if (iorq->timeout
807     && (select_timeout == 0
808     || iorq->timeout < select_timeout))
809     {
810     // Set new timeout
811     select_timeout = iorq->timeout;
812     g_min_timeout_fd = iorq->fd; /* Remember fd */
813     tv->tv_sec = select_timeout / 1000;
814     tv->tv_usec = (select_timeout % 1000) * 1000;
815     *timeout = True;
816     }
817     break;
818    
819     case IRP_MJ_WRITE:
820     FD_SET(iorq->fd, wfds);
821     break;
822    
823     }
824     *n = MAX(*n, iorq->fd);
825     }
826 n-ki 592
827     iorq = iorq->next;
828 n-ki 569 }
829     }
830    
831 n-ki 627 struct async_iorequest *
832     rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq)
833     {
834     if (!iorq)
835     return NULL;
836 n-ki 590
837 n-ki 627 if (iorq->buffer)
838     xfree(iorq->buffer);
839     if (prev)
840     {
841     prev->next = iorq->next;
842     xfree(iorq);
843     iorq = prev->next;
844     }
845     else
846     {
847     // Even if NULL
848     g_iorequest = iorq->next;
849     xfree(iorq);
850     iorq = NULL;
851     }
852     return iorq;
853     }
854    
855 n-ki 569 /* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
856     void
857     rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
858     {
859     NTSTATUS status;
860 n-ki 592 uint32 result = 0;
861 n-ki 569 DEVICE_FNS *fns;
862     struct async_iorequest *iorq;
863 n-ki 592 struct async_iorequest *prev;
864 n-ki 595 uint32 req_size = 0;
865 n-ki 569
866     if (timed_out)
867     {
868     rdpdr_abort_io(g_min_timeout_fd, 0, STATUS_TIMEOUT);
869     return;
870     }
871    
872 n-ki 593 iorq = g_iorequest;
873 n-ki 592 prev = NULL;
874     while (iorq != NULL)
875 n-ki 569 {
876     if (iorq->fd != 0)
877     {
878     switch (iorq->major)
879     {
880     case IRP_MJ_READ:
881     if (FD_ISSET(iorq->fd, rfds))
882     {
883 n-ki 592 /* Read the data */
884 n-ki 569 fns = iorq->fns;
885 n-ki 593
886 n-ki 595 req_size =
887     (iorq->length - iorq->partial_len) >
888     8192 ? 8192 : (iorq->length -
889     iorq->partial_len);
890 n-ki 593 /* never read larger chunks than 8k - chances are that it will block */
891 n-ki 592 status = fns->read(iorq->fd,
892     iorq->buffer + iorq->partial_len,
893 n-ki 613 req_size, iorq->offset, &result);
894 n-ki 595
895 n-ki 627 if (result > 0)
896     {
897     iorq->partial_len += result;
898     iorq->offset += result;
899     }
900 n-ki 569 #if WITH_DEBUG_RDP5
901     DEBUG(("RDPDR: %d bytes of data read\n", result));
902     #endif
903 n-ki 592 /* only delete link if all data has been transfered */
904 n-ki 595 /* or if result was 0 and status success - EOF */
905     if ((iorq->partial_len == iorq->length) ||
906     (result == 0))
907 n-ki 592 {
908 n-ki 595 #if WITH_DEBUG_RDP5
909     DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length));
910     #endif
911 n-ki 592 rdpdr_send_completion(iorq->device,
912     iorq->id, status,
913 n-ki 595 iorq->partial_len,
914     iorq->buffer,
915     iorq->partial_len);
916 n-ki 627 iorq = rdpdr_remove_iorequest(prev, iorq);
917 n-ki 592 }
918 n-ki 569 }
919     break;
920     case IRP_MJ_WRITE:
921     if (FD_ISSET(iorq->fd, wfds))
922     {
923 n-ki 592 /* Write data. */
924 n-ki 569 fns = iorq->fns;
925 n-ki 593
926 n-ki 595 req_size =
927     (iorq->length - iorq->partial_len) >
928     8192 ? 8192 : (iorq->length -
929     iorq->partial_len);
930    
931 n-ki 593 /* never write larger chunks than 8k - chances are that it will block */
932 n-ki 592 status = fns->write(iorq->fd,
933     iorq->buffer +
934 n-ki 613 iorq->partial_len, req_size,
935     iorq->offset, &result);
936 n-ki 627
937     if (result > 0)
938     {
939     iorq->partial_len += result;
940     iorq->offset += result;
941     }
942    
943 n-ki 592 #if WITH_DEBUG_RDP5
944     DEBUG(("RDPDR: %d bytes of data written\n",
945     result));
946     #endif
947     /* only delete link if all data has been transfered */
948 n-ki 595 /* or we couldn't write */
949     if ((iorq->partial_len == iorq->length)
950     || (result == 0))
951 n-ki 592 {
952 n-ki 595 #if WITH_DEBUG_RDP5
953     DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length));
954     #endif
955 n-ki 592 rdpdr_send_completion(iorq->device,
956     iorq->id, status,
957 astrand 608 iorq->partial_len,
958     (uint8 *) "", 1);
959 n-ki 569
960 n-ki 627 iorq = rdpdr_remove_iorequest(prev, iorq);
961 n-ki 592 }
962 n-ki 569 }
963     break;
964     }
965 n-ki 592
966 n-ki 569 }
967 n-ki 592 prev = iorq;
968 n-ki 614 if (iorq)
969     iorq = iorq->next;
970 n-ki 569 }
971 n-ki 592
972 n-ki 569 }
973    
974     /* Abort a pending io request for a given handle and major */
975     BOOL
976     rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status)
977     {
978     uint32 result;
979     struct async_iorequest *iorq;
980 n-ki 592 struct async_iorequest *prev;
981 n-ki 569
982 stargo 602 iorq = g_iorequest;
983 n-ki 592 prev = NULL;
984     while (iorq != NULL)
985 n-ki 569 {
986     // Only remove from table when major is not set, or when correct major is supplied.
987     // Abort read should not abort a write io request.
988     if ((iorq->fd == fd) && (major == 0 || iorq->major == major))
989     {
990     result = 0;
991 astrand 608 rdpdr_send_completion(iorq->device, iorq->id, status, result, (uint8 *) "",
992     1);
993 n-ki 627
994     iorq = rdpdr_remove_iorequest(prev, iorq);
995 n-ki 569 return True;
996     }
997 n-ki 592
998     prev = iorq;
999     iorq = iorq->next;
1000 n-ki 569 }
1001 n-ki 592
1002 n-ki 569 return False;
1003     }

  ViewVC Help
Powered by ViewVC 1.1.26