1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Entrypoint and utility functions
4 Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
5 Copyright (C) Jeroen Meijer <jeroen@oldambt7.com> 2003-2008
6 Copyright (C) Henrik Andersson <hean01@cendio.se> 2013-2017
7
8
9 This program is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /* According to the W2K RDP Printer Redirection WhitePaper, a data
24 * blob is sent to the client after the configuration of the printer
25 * is changed at the server.
26 *
27 * This data blob is saved to the registry. The client returns this
28 * data blob in a new session with the printer announce data.
29 * The data is not interpreted by the client.
30 */
31
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include "rdesktop.h"
39
40 static RD_BOOL
printercache_mkdir(char * base,char * printer)41 printercache_mkdir(char *base, char *printer)
42 {
43 char *path;
44
45 path = (char *) xmalloc(strlen(base) + sizeof("/.rdesktop/rdpdr/") + strlen(printer) + 1);
46
47 sprintf(path, "%s/.rdesktop", base);
48 if ((mkdir(path, 0700) == -1) && errno != EEXIST)
49 {
50 logger(Core, Error, "printercache_mkdir(), mkdir() failed: %s", strerror(errno));
51 xfree(path);
52 return False;
53 }
54
55 strcat(path, "/rdpdr");
56 if ((mkdir(path, 0700) == -1) && errno != EEXIST)
57 {
58 logger(Core, Error, "printercache_mkdir(), mkdir() failed: %s", strerror(errno));
59 xfree(path);
60 return False;
61 }
62
63 strcat(path, "/");
64 strcat(path, printer);
65 if ((mkdir(path, 0700) == -1) && errno != EEXIST)
66 {
67 logger(Core, Error, "printercache_mkdir(), mkdir() failed: %s", strerror(errno));
68 xfree(path);
69 return False;
70 }
71
72 xfree(path);
73 return True;
74 }
75
76 static RD_BOOL
printercache_unlink_blob(char * printer)77 printercache_unlink_blob(char *printer)
78 {
79 char *path;
80 char *home;
81
82 if (printer == NULL)
83 return False;
84
85 home = getenv("HOME");
86 if (home == NULL)
87 return False;
88
89 path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer) +
90 sizeof("/AutoPrinterCacheData") + 1);
91
92 sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer);
93
94 if (unlink(path) < 0)
95 {
96 xfree(path);
97 return False;
98 }
99
100 sprintf(path, "%s/.rdesktop/rdpdr/%s", home, printer);
101
102 if (rmdir(path) < 0)
103 {
104 xfree(path);
105 return False;
106 }
107
108 xfree(path);
109 return True;
110 }
111
112
113 static RD_BOOL
printercache_rename_blob(char * printer,char * new_printer)114 printercache_rename_blob(char *printer, char *new_printer)
115 {
116 char *printer_path;
117 char *new_printer_path;
118 int printer_maxlen;
119
120 char *home;
121
122 if (printer == NULL)
123 return False;
124
125 home = getenv("HOME");
126 if (home == NULL)
127 return False;
128
129 printer_maxlen =
130 (strlen(printer) >
131 strlen(new_printer) ? strlen(printer) : strlen(new_printer)) + strlen(home) +
132 sizeof("/.rdesktop/rdpdr/") + 1;
133
134 printer_path = (char *) xmalloc(printer_maxlen);
135 new_printer_path = (char *) xmalloc(printer_maxlen);
136
137 sprintf(printer_path, "%s/.rdesktop/rdpdr/%s", home, printer);
138 sprintf(new_printer_path, "%s/.rdesktop/rdpdr/%s", home, new_printer);
139
140 logger(Core, Debug, "printercache_rename_blob(), printer_path=%s, new_printer_path=%s",
141 printer_path, new_printer_path);
142 if (rename(printer_path, new_printer_path) < 0)
143 {
144 logger(Core, Error, "printercache_rename_blob(), rename() failed: %s",
145 strerror(errno));
146 xfree(printer_path);
147 xfree(new_printer_path);
148 return False;
149 }
150
151 xfree(printer_path);
152 xfree(new_printer_path);
153 return True;
154 }
155
156
157 int
printercache_load_blob(char * printer_name,uint8 ** data)158 printercache_load_blob(char *printer_name, uint8 ** data)
159 {
160 char *home, *path;
161 struct stat st;
162 int fd, length;
163
164 if (printer_name == NULL)
165 return 0;
166
167 *data = NULL;
168
169 home = getenv("HOME");
170 if (home == NULL)
171 return 0;
172
173 path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer_name) +
174 sizeof("/AutoPrinterCacheData") + 1);
175 sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer_name);
176
177 fd = open(path, O_RDONLY);
178 if (fd == -1)
179 {
180 xfree(path);
181 return 0;
182 }
183
184 if (fstat(fd, &st))
185 {
186 xfree(path);
187 return 0;
188 }
189
190 *data = (uint8 *) xmalloc(st.st_size);
191 length = read(fd, *data, st.st_size);
192 close(fd);
193 xfree(path);
194 return length;
195 }
196
197 static void
printercache_save_blob(char * printer_name,uint8 * data,uint32 length)198 printercache_save_blob(char *printer_name, uint8 * data, uint32 length)
199 {
200 char *home, *path;
201 int fd;
202
203 if (printer_name == NULL)
204 return;
205
206 home = getenv("HOME");
207 if (home == NULL)
208 return;
209
210 if (!printercache_mkdir(home, printer_name))
211 return;
212
213 path = (char *) xmalloc(strlen(home) + sizeof("/.rdesktop/rdpdr/") + strlen(printer_name) +
214 sizeof("/AutoPrinterCacheData") + 1);
215 sprintf(path, "%s/.rdesktop/rdpdr/%s/AutoPrinterCacheData", home, printer_name);
216
217 fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
218 if (fd == -1)
219 {
220 logger(Core, Error, "printercache_save_blob(), open() failed: %s", strerror(errno));
221 xfree(path);
222 return;
223 }
224
225 if (write(fd, data, length) != length)
226 {
227 logger(Core, Error, "printercache_save_blob(), write() failed: %s",
228 strerror(errno));
229 unlink(path);
230 }
231
232 close(fd);
233 xfree(path);
234 }
235
236 void
printercache_process(STREAM s)237 printercache_process(STREAM s)
238 {
239 uint32 type, printer_length, driver_length, printer_unicode_length, blob_length;
240 char device_name[9], *printer, *driver;
241 size_t blob_start;
242 unsigned char *blob;
243
244 printer = driver = NULL;
245
246 in_uint32_le(s, type);
247 switch (type)
248 {
249 case 4: /* rename item */
250 in_uint8(s, printer_length);
251 in_uint8s(s, 0x3); /* padding */
252 in_uint8(s, driver_length);
253 in_uint8s(s, 0x3); /* padding */
254
255 /* NOTE - 'driver' doesn't contain driver, it contains the new printer name */
256
257 rdp_in_unistr(s, printer_length, &printer, &printer_length);
258 rdp_in_unistr(s, driver_length, &driver, &driver_length);
259
260 if (printer != NULL && driver != NULL)
261 printercache_rename_blob(printer, driver);
262
263 free(printer);
264 free(driver);
265 break;
266
267 case 3: /* delete item */
268 in_uint8(s, printer_unicode_length);
269 in_uint8s(s, 0x3); /* padding */
270 rdp_in_unistr(s, printer_unicode_length, &printer, &printer_unicode_length);
271 if (printer)
272 printercache_unlink_blob(printer);
273 free(printer);
274 break;
275
276 case 2: /* save printer data */
277 in_uint32_le(s, printer_unicode_length);
278 in_uint32_le(s, blob_length);
279
280 if (printer_unicode_length < 2 * 255)
281 {
282 rdp_in_unistr(s, printer_unicode_length, &printer,
283 &printer_unicode_length);
284 if (printer) {
285 in_uint8p(s, blob, blob_length);
286 printercache_save_blob(printer, blob, blob_length);
287 }
288 free(printer);
289 }
290 break;
291
292 case 1: /* save device data */
293 in_uint8a(s, device_name, 5); /* get LPTx/COMx name */
294
295 /* need to fetch this data so that we can get the length of the packet to store. */
296 blob_start = s_tell(s);
297 in_uint8s(s, 0x2); /* ??? */
298 in_uint8s(s, 0x2) /* pad?? */
299 in_uint32_be(s, driver_length);
300 in_uint32_be(s, printer_length);
301 in_uint8s(s, 0x7) /* pad?? */
302 /* next is driver in unicode */
303 /* next is printer in unicode */
304 /* TODO: figure out how to use this information when reconnecting */
305 /* actually - all we need to store is the driver and printer */
306 /* and figure out what the first word is. */
307 /* rewind stream so that we can save this blob */
308 /* length is driver_length + printer_length + 19 */
309 /* rewind stream */
310 s_seek(s, blob_start);
311
312 blob_length = driver_length + printer_length + 19;
313 in_uint8p(s, blob, blob_length);
314 printercache_save_blob(device_name, blob, blob_length);
315 break;
316 default:
317 logger(Protocol, Warning,
318 "printercache_process(), unhandled packet type %d", type);
319 break;
320 }
321 }
322