/[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 747 - (hide annotations)
Mon Aug 9 13:50:41 2004 UTC (19 years, 9 months ago) by astrand
File MIME type: text/plain
File size: 23363 byte(s)
Disk redirection actually uses share names; not drive letters.
Make sure we truncate share names longer than 8 chars.
Documentation updated.

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

  ViewVC Help
Powered by ViewVC 1.1.26