/[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 662 by astrand, Fri Apr 16 14:04:02 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                                  in_uint32_le(s, bytes_out);                                  status = STATUS_NOT_SUPPORTED;
640                                  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;  
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                                    status = STATUS_CANCELLED;
652                                    break;
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;
660    
661    
662                    case IRP_MJ_LOCK_CONTROL:
663    
664                            if (g_rdpdr_device[device].device_type != DEVICE_TYPE_DISK)
665                            {
666                                    status = STATUS_INVALID_HANDLE;
667                                    break;
668                            }
669    
670                            in_uint32_le(s, info_level);
671    
672                            out.data = out.p = buffer;
673                            out.size = sizeof(buffer);
674                            /* FIXME: Perhaps consider actually *do*
675                               something here :-) */
676                            status = STATUS_SUCCESS;
677                            result = buffer_len = out.p - out.data;
678                          break;                          break;
679    
680                  default:                  default:
# Line 201  rdpdr_process_irp(STREAM s) Line 682  rdpdr_process_irp(STREAM s)
682                          break;                          break;
683          }          }
684    
685          rdpdr_send_completion(device, id, status, result, buffer, buffer_len);          if (status != STATUS_PENDING)
686            {
687                    rdpdr_send_completion(device, id, status, result, buffer, buffer_len);
688            }
689            if (buffer)
690                    xfree(buffer);
691            buffer = NULL;
692    }
693    
694    void
695    rdpdr_send_clientcapabilty(void)
696    {
697            uint8 magic[4] = "rDPC";
698            STREAM s;
699    
700            s = channel_init(rdpdr_channel, 0x50);
701            out_uint8a(s, magic, 4);
702            out_uint32_le(s, 5);    /* count */
703            out_uint16_le(s, 1);    /* first */
704            out_uint16_le(s, 0x28); /* length */
705            out_uint32_le(s, 1);
706            out_uint32_le(s, 2);
707            out_uint16_le(s, 2);
708            out_uint16_le(s, 5);
709            out_uint16_le(s, 1);
710            out_uint16_le(s, 5);
711            out_uint16_le(s, 0xFFFF);
712            out_uint16_le(s, 0);
713            out_uint32_le(s, 0);
714            out_uint32_le(s, 3);
715            out_uint32_le(s, 0);
716            out_uint32_le(s, 0);
717            out_uint16_le(s, 2);    /* second */
718            out_uint16_le(s, 8);    /* length */
719            out_uint32_le(s, 1);
720            out_uint16_le(s, 3);    /* third */
721            out_uint16_le(s, 8);    /* length */
722            out_uint32_le(s, 1);
723            out_uint16_le(s, 4);    /* fourth */
724            out_uint16_le(s, 8);    /* length */
725            out_uint32_le(s, 1);
726            out_uint16_le(s, 5);    /* fifth */
727            out_uint16_le(s, 8);    /* length */
728            out_uint32_le(s, 1);
729    
730            s_mark_end(s);
731            channel_send(s, rdpdr_channel);
732  }  }
733    
734  static void  static void
735  rdpdr_process(STREAM s)  rdpdr_process(STREAM s)
736  {  {
737          uint32 handle;          uint32 handle;
738          char *magic;          uint8 *magic;
739    
740          printf("rdpdr_process\n");  #if WITH_DEBUG_RDP5
741          hexdump(s->p, s->end-s->p);          printf("--- rdpdr_process ---\n");
742            hexdump(s->p, s->end - s->p);
743    #endif
744          in_uint8p(s, magic, 4);          in_uint8p(s, magic, 4);
745    
746          if ((magic[0] == 'r') && (magic[1] == 'D'))          if ((magic[0] == 'r') && (magic[1] == 'D'))
# Line 225  rdpdr_process(STREAM s) Line 754  rdpdr_process(STREAM s)
754                  {                  {
755                          rdpdr_send_connect();                          rdpdr_send_connect();
756                          rdpdr_send_name();                          rdpdr_send_name();
                         rdpdr_send_available();  
757                          return;                          return;
758                  }                  }
759                  else if ((magic[2] == 'C') && (magic[3] == 'C'))                  if ((magic[2] == 'C') && (magic[3] == 'C'))
760                  {                  {
761                          /* connect from server */                          /* connect from server */
762                            rdpdr_send_clientcapabilty();
763                            rdpdr_send_available();
764                          return;                          return;
765                  }                  }
766                  else if ((magic[2] == 'r') && (magic[3] == 'd'))                  if ((magic[2] == 'r') && (magic[3] == 'd'))
767                  {                  {
768                          /* connect to a specific resource */                          /* connect to a specific resource */
769                          in_uint32(s, handle);                          in_uint32(s, handle);
770                          printf("Server connected to resource %d\n", handle);  #if WITH_DEBUG_RDP5
771                            DEBUG(("RDPDR: Server connected to resource %d\n", handle));
772    #endif
773                            return;
774                    }
775                    if ((magic[2] == 'P') && (magic[3] == 'S'))
776                    {
777                            /* server capability */
778                            return;
779                    }
780            }
781            if ((magic[0] == 'R') && (magic[1] == 'P'))
782            {
783                    if ((magic[2] == 'C') && (magic[3] == 'P'))
784                    {
785                            printercache_process(s);
786                          return;                          return;
787                  }                  }
788          }          }
# Line 245  rdpdr_process(STREAM s) Line 790  rdpdr_process(STREAM s)
790  }  }
791    
792  BOOL  BOOL
793  rdpdr_init(void)  rdpdr_init()
794  {  {
795          rdpdr_channel = channel_register("rdpdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP, rdpdr_process);          if (g_num_devices > 0)
796            {
797                    rdpdr_channel =
798                            channel_register("rdpdr",
799                                             CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP,
800                                             rdpdr_process);
801            }
802    
803          return (rdpdr_channel != NULL);          return (rdpdr_channel != NULL);
804  }  }
805    
806    /* Add file descriptors of pending io request to select() */
807    void
808    rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * timeout)
809    {
810            uint32 select_timeout = 0;      // Timeout value to be used for select() (in millisecons).
811            struct async_iorequest *iorq;
812            char c;
813    
814            iorq = g_iorequest;
815            while (iorq != NULL)
816            {
817                    /* We need to test that the fd is still valid */
818                    if ((iorq->fd != 0) && (read(iorq->fd, &c, 0) == 0))
819                    {
820                            switch (iorq->major)
821                            {
822                                    case IRP_MJ_READ:
823    
824                                            FD_SET(iorq->fd, rfds);
825    
826                                            // Check if io request timeout is smaller than current (but not 0).
827                                            if (iorq->timeout
828                                                && (select_timeout == 0
829                                                    || iorq->timeout < select_timeout))
830                                            {
831                                                    // Set new timeout
832                                                    select_timeout = iorq->timeout;
833                                                    g_min_timeout_fd = iorq->fd;    /* Remember fd */
834                                                    tv->tv_sec = select_timeout / 1000;
835                                                    tv->tv_usec = (select_timeout % 1000) * 1000;
836                                                    *timeout = True;
837                                            }
838                                            break;
839    
840                                    case IRP_MJ_WRITE:
841                                            FD_SET(iorq->fd, wfds);
842                                            break;
843    
844                            }
845                            *n = MAX(*n, iorq->fd);
846                    }
847    
848                    iorq = iorq->next;
849            }
850    }
851    
852    struct async_iorequest *
853    rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq)
854    {
855            if (!iorq)
856                    return NULL;
857    
858            if (iorq->buffer)
859                    xfree(iorq->buffer);
860            if (prev)
861            {
862                    prev->next = iorq->next;
863                    xfree(iorq);
864                    iorq = prev->next;
865            }
866            else
867            {
868                    // Even if NULL
869                    g_iorequest = iorq->next;
870                    xfree(iorq);
871                    iorq = NULL;
872            }
873            return iorq;
874    }
875    
876    /* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
877    void
878    rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
879    {
880            NTSTATUS status;
881            uint32 result = 0;
882            DEVICE_FNS *fns;
883            struct async_iorequest *iorq;
884            struct async_iorequest *prev;
885            uint32 req_size = 0;
886    
887            if (timed_out)
888            {
889                    rdpdr_abort_io(g_min_timeout_fd, 0, STATUS_TIMEOUT);
890                    return;
891            }
892    
893            iorq = g_iorequest;
894            prev = NULL;
895            while (iorq != NULL)
896            {
897                    if (iorq->fd != 0)
898                    {
899                            switch (iorq->major)
900                            {
901                                    case IRP_MJ_READ:
902                                            if (FD_ISSET(iorq->fd, rfds))
903                                            {
904                                                    /* Read the data */
905                                                    fns = iorq->fns;
906    
907                                                    req_size =
908                                                            (iorq->length - iorq->partial_len) >
909                                                            8192 ? 8192 : (iorq->length -
910                                                                           iorq->partial_len);
911                                                    /* never read larger chunks than 8k - chances are that it will block */
912                                                    status = fns->read(iorq->fd,
913                                                                       iorq->buffer + iorq->partial_len,
914                                                                       req_size, iorq->offset, &result);
915    
916                                                    if (result > 0)
917                                                    {
918                                                            iorq->partial_len += result;
919                                                            iorq->offset += result;
920                                                    }
921    #if WITH_DEBUG_RDP5
922                                                    DEBUG(("RDPDR: %d bytes of data read\n", result));
923    #endif
924                                                    /* only delete link if all data has been transfered */
925                                                    /* or if result was 0 and status success - EOF      */
926                                                    if ((iorq->partial_len == iorq->length) ||
927                                                        (result == 0))
928                                                    {
929    #if WITH_DEBUG_RDP5
930                                                            DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length));
931    #endif
932                                                            rdpdr_send_completion(iorq->device,
933                                                                                  iorq->id, status,
934                                                                                  iorq->partial_len,
935                                                                                  iorq->buffer,
936                                                                                  iorq->partial_len);
937                                                            iorq = rdpdr_remove_iorequest(prev, iorq);
938                                                    }
939                                            }
940                                            break;
941                                    case IRP_MJ_WRITE:
942                                            if (FD_ISSET(iorq->fd, wfds))
943                                            {
944                                                    /* Write data. */
945                                                    fns = iorq->fns;
946    
947                                                    req_size =
948                                                            (iorq->length - iorq->partial_len) >
949                                                            8192 ? 8192 : (iorq->length -
950                                                                           iorq->partial_len);
951    
952                                                    /* never write larger chunks than 8k - chances are that it will block */
953                                                    status = fns->write(iorq->fd,
954                                                                        iorq->buffer +
955                                                                        iorq->partial_len, req_size,
956                                                                        iorq->offset, &result);
957    
958                                                    if (result > 0)
959                                                    {
960                                                            iorq->partial_len += result;
961                                                            iorq->offset += result;
962                                                    }
963    
964    #if WITH_DEBUG_RDP5
965                                                    DEBUG(("RDPDR: %d bytes of data written\n",
966                                                           result));
967    #endif
968                                                    /* only delete link if all data has been transfered */
969                                                    /* or we couldn't write */
970                                                    if ((iorq->partial_len == iorq->length)
971                                                        || (result == 0))
972                                                    {
973    #if WITH_DEBUG_RDP5
974                                                            DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length));
975    #endif
976                                                            rdpdr_send_completion(iorq->device,
977                                                                                  iorq->id, status,
978                                                                                  iorq->partial_len,
979                                                                                  (uint8 *) "", 1);
980    
981                                                            iorq = rdpdr_remove_iorequest(prev, iorq);
982                                                    }
983                                            }
984                                            break;
985                            }
986    
987                    }
988                    prev = iorq;
989                    if (iorq)
990                            iorq = iorq->next;
991            }
992    
993    }
994    
995    /* Abort a pending io request for a given handle and major */
996    BOOL
997    rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status)
998    {
999            uint32 result;
1000            struct async_iorequest *iorq;
1001            struct async_iorequest *prev;
1002    
1003            iorq = g_iorequest;
1004            prev = NULL;
1005            while (iorq != NULL)
1006            {
1007                    // Only remove from table when major is not set, or when correct major is supplied.
1008                    // Abort read should not abort a write io request.
1009                    if ((iorq->fd == fd) && (major == 0 || iorq->major == major))
1010                    {
1011                            result = 0;
1012                            rdpdr_send_completion(iorq->device, iorq->id, status, result, (uint8 *) "",
1013                                                  1);
1014    
1015                            iorq = rdpdr_remove_iorequest(prev, iorq);
1016                            return True;
1017                    }
1018    
1019                    prev = iorq;
1020                    iorq = iorq->next;
1021            }
1022    
1023            return False;
1024    }

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

  ViewVC Help
Powered by ViewVC 1.1.26