/[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 1327 - (hide annotations)
Fri Nov 3 19:56:42 2006 UTC (17 years, 7 months ago) by stargo
File MIME type: text/plain
File size: 27400 byte(s)
make sure to lock the datapath of rdpdr_send_completion to prevent
simultaneous access to shared variables in multiple threads

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

  ViewVC Help
Powered by ViewVC 1.1.26