1 |
#include "rdesktop.h" |
2 |
|
3 |
#define IRP_MJ_CREATE 0x00 |
4 |
#define IRP_MJ_CLOSE 0x02 |
5 |
#define IRP_MJ_READ 0x03 |
6 |
#define IRP_MJ_WRITE 0x04 |
7 |
#define IRP_MJ_DEVICE_CONTROL 0x0e |
8 |
|
9 |
extern char hostname[16]; |
10 |
extern DEVICE_FNS serial_fns; |
11 |
extern DEVICE_FNS printer_fns; |
12 |
|
13 |
static VCHANNEL *rdpdr_channel; |
14 |
|
15 |
void |
16 |
rdpdr_send_connect(void) |
17 |
{ |
18 |
uint8 magic[4] = "rDCC"; |
19 |
STREAM s; |
20 |
|
21 |
s = channel_init(rdpdr_channel, 12); |
22 |
out_uint8a(s, magic, 4); |
23 |
out_uint16_le(s, 1); /* unknown */ |
24 |
out_uint16_le(s, 5); |
25 |
out_uint32_be(s, 0x815ed39d); /* IP address (use 127.0.0.1) 0x815ed39d */ |
26 |
s_mark_end(s); |
27 |
channel_send(s, rdpdr_channel); |
28 |
} |
29 |
|
30 |
void |
31 |
rdpdr_send_name(void) |
32 |
{ |
33 |
uint8 magic[4] = "rDNC"; |
34 |
uint32 hostlen = (strlen(hostname)+1)*2; |
35 |
STREAM s; |
36 |
|
37 |
s = channel_init(rdpdr_channel, 16+hostlen); |
38 |
out_uint8a(s, magic, 4); |
39 |
out_uint16_le(s, 0x63); /* unknown */ |
40 |
out_uint16_le(s, 0x72); |
41 |
out_uint32(s, 0); |
42 |
out_uint32_le(s, hostlen); |
43 |
rdp_out_unistr(s, hostname, hostlen-2); |
44 |
s_mark_end(s); |
45 |
channel_send(s, rdpdr_channel); |
46 |
} |
47 |
|
48 |
void |
49 |
rdpdr_send_available(void) |
50 |
{ |
51 |
uint8 magic[4] = "rDAD"; |
52 |
char *driver = "Digital turbo PrintServer 20"; /* Fairly generic PostScript driver */ |
53 |
char *printer = "PostScript"; |
54 |
uint32 driverlen = (strlen(driver)+1)*2; |
55 |
uint32 printerlen = (strlen(printer)+1)*2; |
56 |
STREAM s; |
57 |
|
58 |
s = channel_init(rdpdr_channel, 8+20); |
59 |
out_uint8a(s, magic, 4); |
60 |
out_uint32_le(s, 1); /* Number of devices */ |
61 |
|
62 |
#if 1 |
63 |
out_uint32_le(s, 0x1); /* Device type 0x1 - serial */ |
64 |
out_uint32_le(s, 0); /* Handle */ |
65 |
out_uint8p(s, "COM2", 4); |
66 |
out_uint8s(s, 4); /* Pad to 8 */ |
67 |
out_uint32(s, 0); |
68 |
#endif |
69 |
#if 0 |
70 |
out_uint32_le(s, 0x2); /* Device type 0x2 - parallel */ |
71 |
out_uint32_le(s, 0); |
72 |
out_uint8p(s, "LPT2", 4); |
73 |
out_uint8s(s, 4); |
74 |
out_uint32(s, 0); |
75 |
#endif |
76 |
#if 1 |
77 |
out_uint32_le(s, 0x4); /* Device type 0x4 - printer */ |
78 |
out_uint32_le(s, 1); |
79 |
out_uint8p(s, "PRN1", 4); |
80 |
out_uint8s(s, 4); |
81 |
out_uint32_le(s, 24+driverlen+printerlen); /* length of extra info */ |
82 |
out_uint32_le(s, 2); /* unknown */ |
83 |
out_uint8s(s, 8); /* unknown */ |
84 |
out_uint32_le(s, driverlen); /* length of driver name */ |
85 |
out_uint32_le(s, printerlen); /* length of printer name */ |
86 |
out_uint32(s, 0); /* unknown */ |
87 |
rdp_out_unistr(s, driver, driverlen-2); |
88 |
rdp_out_unistr(s, printer, printerlen-2); |
89 |
#endif |
90 |
#if 0 |
91 |
out_uint32_le(s, 0x8); /* Device type 0x8 - disk */ |
92 |
out_uint32_le(s, 0); |
93 |
out_uint8p(s, "Z:", 2); |
94 |
out_uint8s(s, 6); |
95 |
out_uint32(s, 0); |
96 |
#endif |
97 |
#if 0 |
98 |
out_uint32_le(s, 0x20); /* Device type 0x20 - smart card */ |
99 |
out_uint32_le(s, 0); |
100 |
out_uint8p(s, "SCARD", 5); |
101 |
out_uint8s(s, 3); |
102 |
out_uint32(s, 0); |
103 |
#endif |
104 |
|
105 |
s_mark_end(s); |
106 |
channel_send(s, rdpdr_channel); |
107 |
} |
108 |
|
109 |
void |
110 |
rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, uint8 *buffer, uint32 length) |
111 |
{ |
112 |
uint8 magic[4] = "rDCI"; |
113 |
STREAM s; |
114 |
|
115 |
s = channel_init(rdpdr_channel, 20 + length); |
116 |
out_uint8a(s, magic, 4); |
117 |
out_uint32_le(s, device); |
118 |
out_uint32_le(s, id); |
119 |
out_uint32_le(s, status); |
120 |
out_uint32_le(s, result); |
121 |
out_uint8p(s, buffer, length); |
122 |
s_mark_end(s); |
123 |
hexdump(s->channel_hdr+8, s->end-s->channel_hdr-8); |
124 |
channel_send(s, rdpdr_channel); |
125 |
} |
126 |
|
127 |
static void |
128 |
rdpdr_process_irp(STREAM s) |
129 |
{ |
130 |
uint32 device, file, id, major, minor; |
131 |
NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; |
132 |
uint32 result = 0, length, request, bytes_in, bytes_out; |
133 |
uint8 buffer[256]; |
134 |
uint32 buffer_len = 1; |
135 |
struct stream out; |
136 |
DEVICE_FNS *fns; |
137 |
|
138 |
in_uint32_le(s, device); |
139 |
in_uint32_le(s, file); |
140 |
in_uint32_le(s, id); |
141 |
in_uint32_le(s, major); |
142 |
in_uint32_le(s, minor); |
143 |
|
144 |
memset(buffer, 0, sizeof(buffer)); |
145 |
|
146 |
/* FIXME: this should probably be a more dynamic mapping */ |
147 |
switch (device) |
148 |
{ |
149 |
case 0: |
150 |
fns = &serial_fns; |
151 |
case 1: |
152 |
fns = &printer_fns; |
153 |
default: |
154 |
error("IRP for bad device %ld\n", device); |
155 |
return; |
156 |
} |
157 |
|
158 |
switch (major) |
159 |
{ |
160 |
case IRP_MJ_CREATE: |
161 |
if (fns->create) |
162 |
status = fns->create(&result); |
163 |
break; |
164 |
|
165 |
case IRP_MJ_CLOSE: |
166 |
if (fns->close) |
167 |
status = fns->close(file); |
168 |
break; |
169 |
|
170 |
case IRP_MJ_READ: |
171 |
if (fns->read) |
172 |
{ |
173 |
if (length > sizeof(buffer)) |
174 |
length = sizeof(buffer); |
175 |
status = fns->read(file, buffer, length, &result); |
176 |
buffer_len = result; |
177 |
} |
178 |
break; |
179 |
|
180 |
case IRP_MJ_WRITE: |
181 |
if (fns->write) |
182 |
status = fns->write(file, s->p, length, &result); |
183 |
break; |
184 |
|
185 |
case IRP_MJ_DEVICE_CONTROL: |
186 |
if (fns->device_control) |
187 |
{ |
188 |
in_uint32_le(s, bytes_out); |
189 |
in_uint32_le(s, bytes_in); |
190 |
in_uint32_le(s, request); |
191 |
in_uint8s(s, 0x14); |
192 |
out.data = out.p = buffer; |
193 |
out.size = sizeof(buffer); |
194 |
status = fns->device_control(file, request, s, &out); |
195 |
result = buffer_len = out.p - out.data; |
196 |
} |
197 |
break; |
198 |
|
199 |
default: |
200 |
unimpl("IRP major=0x%x minor=0x%x\n", major, minor); |
201 |
break; |
202 |
} |
203 |
|
204 |
rdpdr_send_completion(device, id, status, result, buffer, buffer_len); |
205 |
} |
206 |
|
207 |
static void |
208 |
rdpdr_process(STREAM s) |
209 |
{ |
210 |
uint32 handle; |
211 |
char *magic; |
212 |
|
213 |
printf("rdpdr_process\n"); |
214 |
hexdump(s->p, s->end-s->p); |
215 |
in_uint8p(s, magic, 4); |
216 |
|
217 |
if ((magic[0] == 'r') && (magic[1] == 'D')) |
218 |
{ |
219 |
if ((magic[2] == 'R') && (magic[3] == 'I')) |
220 |
{ |
221 |
rdpdr_process_irp(s); |
222 |
return; |
223 |
} |
224 |
if ((magic[2] == 'n') && (magic[3] == 'I')) |
225 |
{ |
226 |
rdpdr_send_connect(); |
227 |
rdpdr_send_name(); |
228 |
rdpdr_send_available(); |
229 |
return; |
230 |
} |
231 |
else if ((magic[2] == 'C') && (magic[3] == 'C')) |
232 |
{ |
233 |
/* connect from server */ |
234 |
return; |
235 |
} |
236 |
else if ((magic[2] == 'r') && (magic[3] == 'd')) |
237 |
{ |
238 |
/* connect to a specific resource */ |
239 |
in_uint32(s, handle); |
240 |
printf("Server connected to resource %d\n", handle); |
241 |
return; |
242 |
} |
243 |
} |
244 |
unimpl("RDPDR packet type %c%c%c%c\n", magic[0], magic[1], magic[2], magic[3]); |
245 |
} |
246 |
|
247 |
BOOL |
248 |
rdpdr_init(void) |
249 |
{ |
250 |
rdpdr_channel = channel_register("rdpdr", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_COMPRESS_RDP, rdpdr_process); |
251 |
return (rdpdr_channel != NULL); |
252 |
} |