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