/[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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 432 by matthewc, Tue Jul 1 09:31:25 2003 UTC revision 657 by astrand, Fri Apr 16 11:28:34 2004 UTC
# Line 1  Line 1 
1    /* -*- 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    #include <unistd.h>
37    #include <sys/types.h>
38    #include <sys/time.h>
39    #include <dirent.h>             /* opendir, closedir, readdir */
40    #include <time.h>
41  #include "rdesktop.h"  #include "rdesktop.h"
42    
43  #define IRP_MJ_CREATE           0x00  #define IRP_MJ_CREATE                   0x00
44  #define IRP_MJ_CLOSE            0x02  #define IRP_MJ_CLOSE                    0x02
45  #define IRP_MJ_READ             0x03  #define IRP_MJ_READ                     0x03
46  #define IRP_MJ_WRITE            0x04  #define IRP_MJ_WRITE                    0x04
47  #define IRP_MJ_DEVICE_CONTROL   0x0e  #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    #define IRP_MJ_LOCK_CONTROL             0x11
53    
54    #define IRP_MN_QUERY_DIRECTORY          0x01
55    #define IRP_MN_NOTIFY_CHANGE_DIRECTORY  0x02
56    
57  extern char hostname[16];  extern char hostname[16];
58  extern DEVICE_FNS serial_fns;  extern DEVICE_FNS serial_fns;
59  extern DEVICE_FNS printer_fns;  extern DEVICE_FNS printer_fns;
60    extern DEVICE_FNS parallel_fns;
61    extern DEVICE_FNS disk_fns;
62    extern FILEINFO g_fileinfo[];
63    
64  static VCHANNEL *rdpdr_channel;  static VCHANNEL *rdpdr_channel;
65    
66    /* 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    char *g_rdpdr_clientname = NULL;
73    
74    /* Used to store incoming io request, until they are ready to be completed */
75    /* 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    struct async_iorequest
78    {
79            uint32 fd, major, minor, offset, device, id, length, partial_len;
80            long timeout,           /* Total timeout */
81              itv_timeout;          /* Interval timeout (between serial characters) */
82            uint8 *buffer;
83            DEVICE_FNS *fns;
84    
85            struct async_iorequest *next;   /* next element in list */
86    };
87    
88    struct async_iorequest *g_iorequest;
89    
90    /* 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    void
105    convert_to_unix_filename(char *filename)
106    {
107            char *p;
108    
109            while ((p = strchr(filename, '\\')))
110            {
111                    *p = '/';
112            }
113    }
114    
115    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    /* 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                        DEVICE_FNS * fns, uint32 total_timeout, uint32 interval_timeout, uint8 * buffer,
139                        uint32 offset)
140    {
141            struct async_iorequest *iorq;
142    
143            if (g_iorequest == NULL)
144            {
145                    g_iorequest = (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
146                    if (!g_iorequest)
147                            return False;
148                    g_iorequest->fd = 0;
149                    g_iorequest->next = NULL;
150            }
151    
152            iorq = g_iorequest;
153    
154            while (iorq->fd != 0)
155            {
156                    // create new element if needed
157                    if (iorq->next == NULL)
158                    {
159                            iorq->next =
160                                    (struct async_iorequest *) xmalloc(sizeof(struct async_iorequest));
161                            if (!iorq->next)
162                                    return False;
163                            iorq->next->fd = 0;
164                            iorq->next->next = NULL;
165                    }
166                    iorq = iorq->next;
167            }
168            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            iorq->offset = offset;
179            return True;
180    }
181    
182  void  void
183  rdpdr_send_connect(void)  rdpdr_send_connect(void)
184  {  {
# Line 20  rdpdr_send_connect(void) Line 187  rdpdr_send_connect(void)
187    
188          s = channel_init(rdpdr_channel, 12);          s = channel_init(rdpdr_channel, 12);
189          out_uint8a(s, magic, 4);          out_uint8a(s, magic, 4);
190          out_uint16_le(s, 1); /* unknown */          out_uint16_le(s, 1);    /* unknown */
191          out_uint16_le(s, 5);          out_uint16_le(s, 5);
192          out_uint32_be(s, 0x815ed39d); /* IP address (use 127.0.0.1) 0x815ed39d */          out_uint32_be(s, 0x815ed39d);   /* IP address (use 127.0.0.1) 0x815ed39d */
193          s_mark_end(s);          s_mark_end(s);
194          channel_send(s, rdpdr_channel);          channel_send(s, rdpdr_channel);
195  }  }
196    
197    
198  void  void
199  rdpdr_send_name(void)  rdpdr_send_name(void)
200  {  {
201          uint8 magic[4] = "rDNC";          uint8 magic[4] = "rDNC";
         uint32 hostlen = (strlen(hostname)+1)*2;  
202          STREAM s;          STREAM s;
203            uint32 hostlen;
204    
205            if (NULL == g_rdpdr_clientname)
206            {
207                    g_rdpdr_clientname = hostname;
208            }
209            hostlen = (strlen(g_rdpdr_clientname) + 1) * 2;
210    
211          s = channel_init(rdpdr_channel, 16+hostlen);          s = channel_init(rdpdr_channel, 16 + hostlen);
212          out_uint8a(s, magic, 4);          out_uint8a(s, magic, 4);
213          out_uint16_le(s, 0x63); /* unknown */          out_uint16_le(s, 0x63); /* unknown */
214          out_uint16_le(s, 0x72);          out_uint16_le(s, 0x72);
215          out_uint32(s, 0);          out_uint32(s, 0);
216          out_uint32_le(s, hostlen);          out_uint32_le(s, hostlen);
217          rdp_out_unistr(s, hostname, hostlen-2);          rdp_out_unistr(s, g_rdpdr_clientname, hostlen - 2);
218          s_mark_end(s);          s_mark_end(s);
219          channel_send(s, rdpdr_channel);          channel_send(s, rdpdr_channel);
220  }  }
221    
222    /* 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  void  void
251  rdpdr_send_available(void)  rdpdr_send_available(void)
252  {  {
253    
254          uint8 magic[4] = "rDAD";          uint8 magic[4] = "rDAD";
255          char *driver = "Digital turbo PrintServer 20"; /* Fairly generic PostScript driver */          uint32 driverlen, printerlen, bloblen;
256          char *printer = "PostScript";          int i;
         uint32 driverlen = (strlen(driver)+1)*2;  
         uint32 printerlen = (strlen(printer)+1)*2;  
257          STREAM s;          STREAM s;
258            PRINTER *printerinfo;
259    
260          s = channel_init(rdpdr_channel, 8+20);          s = channel_init(rdpdr_channel, announcedata_size());
261          out_uint8a(s, magic, 4);          out_uint8a(s, magic, 4);
262          out_uint32_le(s, 1); /* Number of devices */          out_uint32_le(s, g_num_devices);
263    
264  #if 1          for (i = 0; i < g_num_devices; i++)
265          out_uint32_le(s, 0x1);  /* Device type 0x1 - serial */          {
266          out_uint32_le(s, 0);    /* Handle */                  out_uint32_le(s, g_rdpdr_device[i].device_type);
267          out_uint8p(s, "COM2", 4);                  out_uint32_le(s, i);    /* RDP Device ID */
268          out_uint8s(s, 4);       /* Pad to 8 */                  out_uint8p(s, g_rdpdr_device[i].name, 8);
269          out_uint32(s, 0);  
270  #endif                  switch (g_rdpdr_device[i].device_type)
271  #if 0                  {
272          out_uint32_le(s, 0x2); /* Device type 0x2 - parallel */                          case DEVICE_TYPE_PRINTER:
273          out_uint32_le(s, 0);                                  printerinfo = (PRINTER *) g_rdpdr_device[i].pdevice_data;
274          out_uint8p(s, "LPT2", 4);  
275          out_uint8s(s, 4);                                  driverlen = 2 * strlen(printerinfo->driver) + 2;
276          out_uint32(s, 0);                                  printerlen = 2 * strlen(printerinfo->printer) + 2;
277  #endif                                  bloblen = printerinfo->bloblen;
278  #if 1  
279          out_uint32_le(s, 0x4); /* Device type 0x4 - printer */                                  out_uint32_le(s, 24 + driverlen + printerlen + bloblen);        /* length of extra info */
280          out_uint32_le(s, 1);                                  out_uint32_le(s, printerinfo->default_printer ? 2 : 0);
281          out_uint8p(s, "PRN1", 4);                                  out_uint8s(s, 8);       /* unknown */
282          out_uint8s(s, 4);                                  out_uint32_le(s, driverlen);
283          out_uint32_le(s, 24+driverlen+printerlen); /* length of extra info */                                  out_uint32_le(s, printerlen);
284          out_uint32_le(s, 2); /* unknown */                                  out_uint32_le(s, bloblen);
285          out_uint8s(s, 8); /* unknown */                                  rdp_out_unistr(s, printerinfo->driver, driverlen - 2);
286          out_uint32_le(s, driverlen); /* length of driver name */                                  rdp_out_unistr(s, printerinfo->printer, printerlen - 2);
287          out_uint32_le(s, printerlen); /* length of printer name */                                  out_uint8a(s, printerinfo->blob, bloblen);
288          out_uint32(s, 0); /* unknown */  
289          rdp_out_unistr(s, driver, driverlen-2);                                  if (printerinfo->blob)
290          rdp_out_unistr(s, printer, printerlen-2);                                          xfree(printerinfo->blob);       /* Blob is sent twice if reconnecting */
291  #endif                                  break;
292  #if 0                          default:
293          out_uint32_le(s, 0x8); /* Device type 0x8 - disk */                                  out_uint32(s, 0);
294          out_uint32_le(s, 0);                  }
295          out_uint8p(s, "Z:", 2);          }
         out_uint8s(s, 6);  
         out_uint32(s, 0);  
 #endif  
296  #if 0  #if 0
297          out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */          out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */
298          out_uint32_le(s, 0);          out_uint32_le(s, 0);
299          out_uint8p(s, "SCARD", 5);          out_uint8p(s, "SCARD", 5);
300          out_uint8s(s, 3);          out_uint8s(s, 3);
# Line 107  rdpdr_send_available(void) Line 306  rdpdr_send_available(void)
306  }  }
307    
308  void  void
309  rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 *buffer, uint32 length)  rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 * buffer,
310                          uint32 length)
311  {  {
312          uint8 magic[4] = "rDCI";          uint8 magic[4] = "rDCI";
313          STREAM s;          STREAM s;
# Line 120  rdpdr_send_completion(uint32 device, uin Line 320  rdpdr_send_completion(uint32 device, uin
320          out_uint32_le(s, result);          out_uint32_le(s, result);
321          out_uint8p(s, buffer, length);          out_uint8p(s, buffer, length);
322          s_mark_end(s);          s_mark_end(s);
323          hexdump(s->channel_hdr+8, s->end-s->channel_hdr-8);          /* JIF
324               hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
325          channel_send(s, rdpdr_channel);          channel_send(s, rdpdr_channel);
326  }  }
327    
328  static void  static void
329  rdpdr_process_irp(STREAM s)  rdpdr_process_irp(STREAM s)
330  {  {
331          uint32 device, file, id, major, minor;          uint32 result = 0,
332          NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;                  length = 0,
333          uint32 result = 0, length, request, bytes_in, bytes_out;                  desired_access = 0,
334          uint8 buffer[256];                  request,
335          uint32 buffer_len = 1;                  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          struct stream out;          struct stream out;
351          DEVICE_FNS *fns;          DEVICE_FNS *fns;
352            BOOL rw_blocking = True;
353            NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
354    
355          in_uint32_le(s, device);          in_uint32_le(s, device);
356          in_uint32_le(s, file);          in_uint32_le(s, file);
# Line 141  rdpdr_process_irp(STREAM s) Line 358  rdpdr_process_irp(STREAM s)
358          in_uint32_le(s, major);          in_uint32_le(s, major);
359          in_uint32_le(s, minor);          in_uint32_le(s, minor);
360    
361          memset(buffer, 0, sizeof(buffer));          buffer_len = 0;
362            buffer = (uint8 *) xmalloc(1024);
363            buffer[0] = 0;
364    
365          /* FIXME: this should probably be a more dynamic mapping */          switch (g_rdpdr_device[device].device_type)
         switch (device)  
366          {          {
367                  case 0:                  case DEVICE_TYPE_SERIAL:
368    
369                          fns = &serial_fns;                          fns = &serial_fns;
370                  case 1:                          rw_blocking = False;
371                            break;
372    
373                    case DEVICE_TYPE_PARALLEL:
374    
375                            fns = &parallel_fns;
376                            rw_blocking = False;
377                            break;
378    
379                    case DEVICE_TYPE_PRINTER:
380    
381                          fns = &printer_fns;                          fns = &printer_fns;
382                            break;
383    
384                    case DEVICE_TYPE_DISK:
385    
386                            fns = &disk_fns;
387                            rw_blocking = False;
388                            break;
389    
390                    case DEVICE_TYPE_SCARD:
391                  default:                  default:
392    
393                          error("IRP for bad device %ld\n", device);                          error("IRP for bad device %ld\n", device);
394                          return;                          return;
395          }          }
# Line 158  rdpdr_process_irp(STREAM s) Line 397  rdpdr_process_irp(STREAM s)
397          switch (major)          switch (major)
398          {          {
399                  case IRP_MJ_CREATE:                  case IRP_MJ_CREATE:
400                          if (fns->create)  
401                                  status = fns->create(&result);                          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                          break;                          break;
429    
430                  case IRP_MJ_CLOSE:                  case IRP_MJ_CLOSE:
431                          if (fns->close)                          if (!fns->close)
432                                  status = fns->close(file);                          {
433                                    status = STATUS_NOT_SUPPORTED;
434                                    break;
435                            }
436    
437                            status = fns->close(file);
438                          break;                          break;
439    
440                  case IRP_MJ_READ:                  case IRP_MJ_READ:
441                          if (fns->read)  
442                            if (!fns->read)
443                            {
444                                    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                            if (!rdpdr_handle_ok(device, file))
454                            {
455                                    status = STATUS_INVALID_HANDLE;
456                                    break;
457                            }
458    
459                            if (rw_blocking)        // Complete read immediately
460                          {                          {
461                                  if (length > sizeof(buffer))                                  buffer = (uint8 *) xrealloc((void *) buffer, length);
462                                          length = sizeof(buffer);                                  if (!buffer)
463                                  status = fns->read(file, buffer, length, &result);                                  {
464                                            status = STATUS_CANCELLED;
465                                            break;
466                                    }
467                                    status = fns->read(file, buffer, length, offset, &result);
468                                  buffer_len = result;                                  buffer_len = result;
469                                    break;
470                          }                          }
                         break;  
471    
472                            // Add request to table
473                            pst_buf = (uint8 *) xmalloc(length);
474                            if (!pst_buf)
475                            {
476                                    status = STATUS_CANCELLED;
477                                    break;
478                            }
479                            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                                 pst_buf, offset))
483                            {
484                                    status = STATUS_PENDING;
485                                    break;
486                            }
487    
488                            status = STATUS_CANCELLED;
489                            break;
490                  case IRP_MJ_WRITE:                  case IRP_MJ_WRITE:
491                          if (fns->write)  
492                                  status = fns->write(file, s->p, length, &result);                          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                            if (!rdpdr_handle_ok(device, file))
507                            {
508                                    status = STATUS_INVALID_HANDLE;
509                                    break;
510                            }
511    
512                            if (rw_blocking)        // Complete immediately
513                            {
514                                    status = fns->write(file, s->p, length, offset, &result);
515                                    break;
516                            }
517    
518                            // Add to table
519                            pst_buf = (uint8 *) xmalloc(length);
520                            if (!pst_buf)
521                            {
522                                    status = STATUS_CANCELLED;
523                                    break;
524                            }
525    
526                            in_uint8a(s, pst_buf, length);
527    
528                            if (add_async_iorequest
529                                (device, file, id, major, length, fns, 0, 0, pst_buf, offset))
530                            {
531                                    status = STATUS_PENDING;
532                                    break;
533                            }
534    
535                            status = STATUS_CANCELLED;
536                            break;
537    
538                    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;                          break;
634    
635                  case IRP_MJ_DEVICE_CONTROL:                  case IRP_MJ_DEVICE_CONTROL:
636                          if (fns->device_control)  
637                            if (!fns->device_control)
638                            {
639                                    status = STATUS_NOT_SUPPORTED;
640                                    break;
641                            }
642    
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                            if (!buffer)
650                          {                          {
651                                  in_uint32_le(s, bytes_out);                                  status = STATUS_CANCELLED;
652                                  in_uint32_le(s, bytes_in);                                  break;
                                 in_uint32_le(s, request);  
                                 in_uint8s(s, 0x14);  
                                 out.data = out.p = buffer;  
                                 out.size = sizeof(buffer);  
                                 status = fns->device_control(file, request, s, &out);  
                                 result = buffer_len = out.p - out.data;  
653                          }                          }
654    
655                            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                          break;                          break;
660    
661                  default:                  default:
# Line 201  rdpdr_process_irp(STREAM s) Line 663  rdpdr_process_irp(STREAM s)
663                          break;                          break;
664          }          }
665    
666          rdpdr_send_completion(device, id, status, result, buffer, buffer_len);          if (status != STATUS_PENDING)
667            {
668                    rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
669            }
670            if (buffer)
671                    xfree(buffer);
672            buffer = NULL;
673    }
674    
675    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  static void  static void
716  rdpdr_process(STREAM s)  rdpdr_process(STREAM s)
717  {  {
718          uint32 handle;          uint32 handle;
719          char *magic;          uint8 *magic;
720    
721          printf("rdpdr_process\n");  #if WITH_DEBUG_RDP5
722          hexdump(s->p, s->end-s->p);          printf("--- rdpdr_process ---\n");
723            hexdump(s->p, s->end - s->p);
724    #endif
725          in_uint8p(s, magic, 4);          in_uint8p(s, magic, 4);
726    
727          if ((magic[0] == 'r') && (magic[1] == 'D'))          if ((magic[0] == 'r') && (magic[1] == 'D'))
# Line 225  rdpdr_process(STREAM s) Line 735  rdpdr_process(STREAM s)
735                  {                  {
736                          rdpdr_send_connect();                          rdpdr_send_connect();
737                          rdpdr_send_name();                          rdpdr_send_name();
                         rdpdr_send_available();  
738                          return;                          return;
739                  }                  }
740                  else if ((magic[2] == 'C') && (magic[3] == 'C'))                  if ((magic[2] == 'C') && (magic[3] == 'C'))
741                  {                  {
742                          /* connect from server */                          /* connect from server */
743                            rdpdr_send_clientcapabilty();
744                            rdpdr_send_available();
745                          return;                          return;
746                  }                  }
747                  else if ((magic[2] == 'r') && (magic[3] == 'd'))                  if ((magic[2] == 'r') && (magic[3] == 'd'))
748                  {                  {
749                          /* connect to a specific resource */                          /* connect to a specific resource */
750                          in_uint32(s, handle);                          in_uint32(s, handle);
751                          printf("Server connected to resource %d\n", handle);  #if WITH_DEBUG_RDP5
752                            DEBUG(("RDPDR: Server connected to resource %d\n", handle));
753    #endif
754                            return;
755                    }
756                    if ((magic[2] == 'P') && (magic[3] == 'S'))
757                    {
758                            /* server capability */
759                            return;
760                    }
761            }
762            if ((magic[0] == 'R') && (magic[1] == 'P'))
763            {
764                    if ((magic[2] == 'C') && (magic[3] == 'P'))
765                    {
766                            printercache_process(s);
767                          return;                          return;
768                  }                  }
769          }          }
# Line 245  rdpdr_process(STREAM s) Line 771  rdpdr_process(STREAM s)
771  }  }
772    
773  BOOL  BOOL
774  rdpdr_init(void)  rdpdr_init()
775  {  {
776          rdpdr_channel = channel_register("rdpdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP, rdpdr_process);          if (g_num_devices > 0)
777            {
778                    rdpdr_channel =
779                            channel_register("rdpdr",
780                                             CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP,
781                                             rdpdr_process);
782            }
783    
784          return (rdpdr_channel != NULL);          return (rdpdr_channel != NULL);
785  }  }
786    
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            uint32 select_timeout = 0;      // Timeout value to be used for select() (in millisecons).
792            struct async_iorequest *iorq;
793    
794            iorq = g_iorequest;
795            while (iorq != NULL)
796            {
797                    if (iorq->fd != 0)
798                    {
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    
827                    iorq = iorq->next;
828            }
829    }
830    
831    struct async_iorequest *
832    rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq)
833    {
834            if (!iorq)
835                    return NULL;
836    
837            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    /* 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            uint32 result = 0;
861            DEVICE_FNS *fns;
862            struct async_iorequest *iorq;
863            struct async_iorequest *prev;
864            uint32 req_size = 0;
865    
866            if (timed_out)
867            {
868                    rdpdr_abort_io(g_min_timeout_fd, 0, STATUS_TIMEOUT);
869                    return;
870            }
871    
872            iorq = g_iorequest;
873            prev = NULL;
874            while (iorq != NULL)
875            {
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                                                    /* Read the data */
884                                                    fns = iorq->fns;
885    
886                                                    req_size =
887                                                            (iorq->length - iorq->partial_len) >
888                                                            8192 ? 8192 : (iorq->length -
889                                                                           iorq->partial_len);
890                                                    /* never read larger chunks than 8k - chances are that it will block */
891                                                    status = fns->read(iorq->fd,
892                                                                       iorq->buffer + iorq->partial_len,
893                                                                       req_size, iorq->offset, &result);
894    
895                                                    if (result > 0)
896                                                    {
897                                                            iorq->partial_len += result;
898                                                            iorq->offset += result;
899                                                    }
900    #if WITH_DEBUG_RDP5
901                                                    DEBUG(("RDPDR: %d bytes of data read\n", result));
902    #endif
903                                                    /* only delete link if all data has been transfered */
904                                                    /* or if result was 0 and status success - EOF      */
905                                                    if ((iorq->partial_len == iorq->length) ||
906                                                        (result == 0))
907                                                    {
908    #if WITH_DEBUG_RDP5
909                                                            DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length));
910    #endif
911                                                            rdpdr_send_completion(iorq->device,
912                                                                                  iorq->id, status,
913                                                                                  iorq->partial_len,
914                                                                                  iorq->buffer,
915                                                                                  iorq->partial_len);
916                                                            iorq = rdpdr_remove_iorequest(prev, iorq);
917                                                    }
918                                            }
919                                            break;
920                                    case IRP_MJ_WRITE:
921                                            if (FD_ISSET(iorq->fd, wfds))
922                                            {
923                                                    /* Write data. */
924                                                    fns = iorq->fns;
925    
926                                                    req_size =
927                                                            (iorq->length - iorq->partial_len) >
928                                                            8192 ? 8192 : (iorq->length -
929                                                                           iorq->partial_len);
930    
931                                                    /* never write larger chunks than 8k - chances are that it will block */
932                                                    status = fns->write(iorq->fd,
933                                                                        iorq->buffer +
934                                                                        iorq->partial_len, req_size,
935                                                                        iorq->offset, &result);
936    
937                                                    if (result > 0)
938                                                    {
939                                                            iorq->partial_len += result;
940                                                            iorq->offset += result;
941                                                    }
942    
943    #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                                                    /* or we couldn't write */
949                                                    if ((iorq->partial_len == iorq->length)
950                                                        || (result == 0))
951                                                    {
952    #if WITH_DEBUG_RDP5
953                                                            DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length));
954    #endif
955                                                            rdpdr_send_completion(iorq->device,
956                                                                                  iorq->id, status,
957                                                                                  iorq->partial_len,
958                                                                                  (uint8 *) "", 1);
959    
960                                                            iorq = rdpdr_remove_iorequest(prev, iorq);
961                                                    }
962                                            }
963                                            break;
964                            }
965    
966                    }
967                    prev = iorq;
968                    if (iorq)
969                            iorq = iorq->next;
970            }
971    
972    }
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            struct async_iorequest *prev;
981    
982            iorq = g_iorequest;
983            prev = NULL;
984            while (iorq != NULL)
985            {
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                            rdpdr_send_completion(iorq->device, iorq->id, status, result, (uint8 *) "",
992                                                  1);
993    
994                            iorq = rdpdr_remove_iorequest(prev, iorq);
995                            return True;
996                    }
997    
998                    prev = iorq;
999                    iorq = iorq->next;
1000            }
1001    
1002            return False;
1003    }

Legend:
Removed from v.432  
changed lines
  Added in v.657

  ViewVC Help
Powered by ViewVC 1.1.26