/[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 554 by stargo, Tue Dec 9 09:57:44 2003 UTC revision 660 by astrand, Fri Apr 16 12:20:56 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 27  rdpdr_send_connect(void) Line 194  rdpdr_send_connect(void)
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);
# Line 40  rdpdr_send_name(void) Line 214  rdpdr_send_name(void)
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, "COM4", 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);
# Line 121  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 142  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 159  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 202  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
# Line 211  rdpdr_process(STREAM s) Line 737  rdpdr_process(STREAM s)
737          uint32 handle;          uint32 handle;
738          uint8 *magic;          uint8 *magic;
739    
740          printf("rdpdr_process\n");  #if WITH_DEBUG_RDP5
741            printf("--- rdpdr_process ---\n");
742          hexdump(s->p, s->end - s->p);          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 226  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 246  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 =          if (g_num_devices > 0)
796                  channel_register("rdpdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP,          {
797                                   rdpdr_process);                  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    
813            iorq = g_iorequest;
814            while (iorq != NULL)
815            {
816                    if (iorq->fd != 0)
817                    {
818                            switch (iorq->major)
819                            {
820                                    case IRP_MJ_READ:
821    
822                                            FD_SET(iorq->fd, rfds);
823    
824                                            // Check if io request timeout is smaller than current (but not 0).
825                                            if (iorq->timeout
826                                                && (select_timeout == 0
827                                                    || iorq->timeout < select_timeout))
828                                            {
829                                                    // Set new timeout
830                                                    select_timeout = iorq->timeout;
831                                                    g_min_timeout_fd = iorq->fd;    /* Remember fd */
832                                                    tv->tv_sec = select_timeout / 1000;
833                                                    tv->tv_usec = (select_timeout % 1000) * 1000;
834                                                    *timeout = True;
835                                            }
836                                            break;
837    
838                                    case IRP_MJ_WRITE:
839                                            FD_SET(iorq->fd, wfds);
840                                            break;
841    
842                            }
843                            *n = MAX(*n, iorq->fd);
844                    }
845    
846                    iorq = iorq->next;
847            }
848    }
849    
850    struct async_iorequest *
851    rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *iorq)
852    {
853            if (!iorq)
854                    return NULL;
855    
856            if (iorq->buffer)
857                    xfree(iorq->buffer);
858            if (prev)
859            {
860                    prev->next = iorq->next;
861                    xfree(iorq);
862                    iorq = prev->next;
863            }
864            else
865            {
866                    // Even if NULL
867                    g_iorequest = iorq->next;
868                    xfree(iorq);
869                    iorq = NULL;
870            }
871            return iorq;
872    }
873    
874    /* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
875    void
876    rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
877    {
878            NTSTATUS status;
879            uint32 result = 0;
880            DEVICE_FNS *fns;
881            struct async_iorequest *iorq;
882            struct async_iorequest *prev;
883            uint32 req_size = 0;
884    
885            if (timed_out)
886            {
887                    rdpdr_abort_io(g_min_timeout_fd, 0, STATUS_TIMEOUT);
888                    return;
889            }
890    
891            iorq = g_iorequest;
892            prev = NULL;
893            while (iorq != NULL)
894            {
895                    if (iorq->fd != 0)
896                    {
897                            switch (iorq->major)
898                            {
899                                    case IRP_MJ_READ:
900                                            if (FD_ISSET(iorq->fd, rfds))
901                                            {
902                                                    /* Read the data */
903                                                    fns = iorq->fns;
904    
905                                                    req_size =
906                                                            (iorq->length - iorq->partial_len) >
907                                                            8192 ? 8192 : (iorq->length -
908                                                                           iorq->partial_len);
909                                                    /* never read larger chunks than 8k - chances are that it will block */
910                                                    status = fns->read(iorq->fd,
911                                                                       iorq->buffer + iorq->partial_len,
912                                                                       req_size, iorq->offset, &result);
913    
914                                                    if (result > 0)
915                                                    {
916                                                            iorq->partial_len += result;
917                                                            iorq->offset += result;
918                                                    }
919    #if WITH_DEBUG_RDP5
920                                                    DEBUG(("RDPDR: %d bytes of data read\n", result));
921    #endif
922                                                    /* only delete link if all data has been transfered */
923                                                    /* or if result was 0 and status success - EOF      */
924                                                    if ((iorq->partial_len == iorq->length) ||
925                                                        (result == 0))
926                                                    {
927    #if WITH_DEBUG_RDP5
928                                                            DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length));
929    #endif
930                                                            rdpdr_send_completion(iorq->device,
931                                                                                  iorq->id, status,
932                                                                                  iorq->partial_len,
933                                                                                  iorq->buffer,
934                                                                                  iorq->partial_len);
935                                                            iorq = rdpdr_remove_iorequest(prev, iorq);
936                                                    }
937                                            }
938                                            break;
939                                    case IRP_MJ_WRITE:
940                                            if (FD_ISSET(iorq->fd, wfds))
941                                            {
942                                                    /* Write data. */
943                                                    fns = iorq->fns;
944    
945                                                    req_size =
946                                                            (iorq->length - iorq->partial_len) >
947                                                            8192 ? 8192 : (iorq->length -
948                                                                           iorq->partial_len);
949    
950                                                    /* never write larger chunks than 8k - chances are that it will block */
951                                                    status = fns->write(iorq->fd,
952                                                                        iorq->buffer +
953                                                                        iorq->partial_len, req_size,
954                                                                        iorq->offset, &result);
955    
956                                                    if (result > 0)
957                                                    {
958                                                            iorq->partial_len += result;
959                                                            iorq->offset += result;
960                                                    }
961    
962    #if WITH_DEBUG_RDP5
963                                                    DEBUG(("RDPDR: %d bytes of data written\n",
964                                                           result));
965    #endif
966                                                    /* only delete link if all data has been transfered */
967                                                    /* or we couldn't write */
968                                                    if ((iorq->partial_len == iorq->length)
969                                                        || (result == 0))
970                                                    {
971    #if WITH_DEBUG_RDP5
972                                                            DEBUG(("RDPDR: AIO total %u bytes written of %u\n", iorq->partial_len, iorq->length));
973    #endif
974                                                            rdpdr_send_completion(iorq->device,
975                                                                                  iorq->id, status,
976                                                                                  iorq->partial_len,
977                                                                                  (uint8 *) "", 1);
978    
979                                                            iorq = rdpdr_remove_iorequest(prev, iorq);
980                                                    }
981                                            }
982                                            break;
983                            }
984    
985                    }
986                    prev = iorq;
987                    if (iorq)
988                            iorq = iorq->next;
989            }
990    
991    }
992    
993    /* Abort a pending io request for a given handle and major */
994    BOOL
995    rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status)
996    {
997            uint32 result;
998            struct async_iorequest *iorq;
999            struct async_iorequest *prev;
1000    
1001            iorq = g_iorequest;
1002            prev = NULL;
1003            while (iorq != NULL)
1004            {
1005                    // Only remove from table when major is not set, or when correct major is supplied.
1006                    // Abort read should not abort a write io request.
1007                    if ((iorq->fd == fd) && (major == 0 || iorq->major == major))
1008                    {
1009                            result = 0;
1010                            rdpdr_send_completion(iorq->device, iorq->id, status, result, (uint8 *) "",
1011                                                  1);
1012    
1013                            iorq = rdpdr_remove_iorequest(prev, iorq);
1014                            return True;
1015                    }
1016    
1017                    prev = iorq;
1018                    iorq = iorq->next;
1019            }
1020    
1021            return False;
1022    }

Legend:
Removed from v.554  
changed lines
  Added in v.660

  ViewVC Help
Powered by ViewVC 1.1.26