VirtualBox

source: vbox/trunk/src/VBox/RDP/client-1.8.3/ctrl.c@ 55121

最後變更 在這個檔案從55121是 55121,由 vboxsync 提交於 10 年 前

rdesktop 1.8.3 unmodified

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 10.5 KB
 
1/* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Master/Slave remote controlling
4 Copyright 2013 Henrik Andersson <[email protected]> for Cendio AB
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18*/
19#include "rdesktop.h"
20#include "ssl.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <sys/stat.h>
27#include <sys/un.h>
28#include <limits.h>
29#include <unistd.h>
30
31#define CTRL_LINEBUF_SIZE 1024
32#define CTRL_RESULT_SIZE 32
33#define RDESKTOP_CTRLSOCK_STORE "/.local/share/rdesktop/ctrl"
34
35#define CTRL_HASH_FLAG_SEAMLESS 1
36
37#define ERR_RESULT_OK 0x00
38#define ERR_RESULT_NO_SUCH_COMMAND 0xffffffff
39
40extern RD_BOOL g_seamless_rdp;
41extern uint8 g_static_rdesktop_salt_16[];
42
43static RD_BOOL _ctrl_is_slave;
44static int ctrlsock;
45static char ctrlsock_name[PATH_MAX];
46static struct _ctrl_slave_t *_ctrl_slaves;
47
48#define CMD_SEAMLESS_SPAWN "seamless.spawn"
49
50typedef struct _ctrl_slave_t
51{
52 struct _ctrl_slave_t *prev, *next;
53 int sock;
54 char linebuf[CTRL_LINEBUF_SIZE];
55} _ctrl_slave_t;
56
57
58static void
59_ctrl_slave_new(int sock)
60{
61 _ctrl_slave_t *it, *ns;
62
63 /* initialize new slave list item */
64 ns = (_ctrl_slave_t *) xmalloc(sizeof(_ctrl_slave_t));
65 memset(ns, 0, sizeof(_ctrl_slave_t));
66 ns->sock = sock;
67
68 /* append new slave to end of list */
69 it = _ctrl_slaves;
70
71 /* find last element in list */
72 while (it && it->next)
73 it = it->next;
74
75 /* if last found append new */
76 if (it)
77 {
78 it->next = ns;
79 ns->prev = it;
80 }
81 else
82 {
83 /* no elemnts in list, lets add first */
84 _ctrl_slaves = ns;
85 }
86}
87
88static void
89_ctrl_slave_disconnect(int sock)
90{
91 _ctrl_slave_t *it;
92
93 if (!_ctrl_slaves)
94 return;
95
96 it = _ctrl_slaves;
97
98 /* find slave with sock */
99 while (it->next && it->sock != sock)
100 it = it->next;
101
102 if (it->sock == sock)
103 {
104 /* shutdown socket */
105 shutdown(sock, SHUT_RDWR);
106 close(sock);
107
108 /* remove item from list */
109 if (it == _ctrl_slaves)
110 {
111 if (it->next)
112 _ctrl_slaves = it->next;
113 else
114 _ctrl_slaves = NULL;
115 }
116
117 if (it->prev)
118 {
119 (it->prev)->next = it->next;
120 if (it->next)
121 (it->next)->prev = it->prev;
122 }
123 else if (it->next)
124 (it->next)->prev = NULL;
125
126 xfree(it);
127
128 }
129}
130
131static void
132_ctrl_command_result(_ctrl_slave_t * slave, int result)
133{
134 char buf[64] = { 0 };
135
136 /* translate and send result code back to client */
137 if (result == 0)
138 send(slave->sock, "OK\n", 3, 0);
139 else
140 {
141 snprintf(buf, 64, "ERROR %x\n", result);
142 send(slave->sock, buf, strlen(buf), 0);
143 }
144}
145
146static void
147_ctrl_dispatch_command(_ctrl_slave_t * slave)
148{
149 char *p;
150 char *cmd;
151 unsigned int res;
152
153 /* unescape linebuffer */
154 cmd = utils_string_unescape(slave->linebuf);
155 if (strncmp(cmd, CMD_SEAMLESS_SPAWN " ", strlen(CMD_SEAMLESS_SPAWN) + 1) == 0)
156 {
157 /* process seamless spawn request */
158 p = strstr(cmd, "seamlessrdpshell.exe");
159 if (p)
160 p += strlen("seamlessrdpshell.exe") + 1;
161 else
162 p = cmd + strlen(CMD_SEAMLESS_SPAWN) + 1;
163
164 res = ERR_RESULT_OK;
165
166 if (seamless_send_spawn(p) == (unsigned int) -1)
167 res = 1;
168 }
169 else
170 {
171 res = ERR_RESULT_NO_SUCH_COMMAND;
172 }
173 xfree(cmd);
174
175 _ctrl_command_result(slave, res);
176}
177
178static RD_BOOL
179_ctrl_verify_unix_socket()
180{
181 int s, len;
182 struct sockaddr_un saun;
183
184 memset(&saun, 0, sizeof(struct sockaddr_un));
185
186 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
187 {
188 perror("Error creating ctrl client socket: socket()");
189 exit(1);
190 }
191
192 saun.sun_family = AF_UNIX;
193 strcpy(saun.sun_path, ctrlsock_name);
194 len = sizeof(saun.sun_family) + strlen(saun.sun_path);
195
196 /* test connection */
197 if (connect(s, (struct sockaddr *) &saun, len) != 0)
198 return False;
199
200 shutdown(s, SHUT_RDWR);
201 close(s);
202 return True;
203}
204
205
206static void
207_ctrl_create_hash(const char *user, const char *domain, const char *host, char *hash, size_t hsize)
208{
209 RDSSL_SHA1 sha1;
210 uint8 out[20], delim;
211 uint16 version;
212 uint32 flags;
213
214 /* version\0user\0domain\0host\0flags */
215 flags = 0;
216 delim = '\0';
217 version = 0x0100;
218
219 if (g_seamless_rdp)
220 flags = CTRL_HASH_FLAG_SEAMLESS;
221
222 rdssl_sha1_init(&sha1);
223 rdssl_sha1_update(&sha1, (uint8 *) & version, sizeof(version));
224 rdssl_sha1_update(&sha1, &delim, 1);
225
226 if (user)
227 rdssl_sha1_update(&sha1, (uint8 *) user, strlen(user));
228 rdssl_sha1_update(&sha1, &delim, 1);
229
230 if (domain)
231 rdssl_sha1_update(&sha1, (uint8 *) domain, strlen(domain));
232 rdssl_sha1_update(&sha1, &delim, 1);
233
234 if (host)
235 rdssl_sha1_update(&sha1, (uint8 *) host, strlen(host));
236 rdssl_sha1_update(&sha1, &delim, 1);
237
238 rdssl_sha1_update(&sha1, (uint8 *) & flags, sizeof(flags));
239 rdssl_sha1_final(&sha1, out);
240
241 sec_hash_to_string(hash, hsize, out, sizeof(out));
242}
243
244
245/** Initialize ctrl
246 Ret values: <0 failure, 0 master, 1 client
247 */
248int
249ctrl_init(const char *user, const char *domain, const char *host)
250{
251 struct stat st;
252 struct sockaddr_un saun;
253 char hash[41], path[PATH_MAX];
254 char *home;
255
256 /* check if ctrl already initialized */
257 if (ctrlsock != 0 || _ctrl_is_slave)
258 return 0;
259
260 home = getenv("HOME");
261 if (home == NULL)
262 {
263 return -1;
264 }
265
266 /* get uniq hash for ctrlsock name */
267 _ctrl_create_hash(user, domain, host, hash, 41);
268 snprintf(ctrlsock_name, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE "/%s.ctl", home, hash);
269 ctrlsock_name[sizeof(ctrlsock_name) - 1] = '\0';
270
271 /* make sure that ctrlsock store path exists */
272 snprintf(path, PATH_MAX, "%s" RDESKTOP_CTRLSOCK_STORE, home);
273 path[sizeof(path) - 1] = '\0';
274 if (utils_mkdir_p(path, 0700) == -1)
275 {
276 perror(path);
277 return -1;
278 }
279
280 /* check if ctrl socket already exist then this process becomes a client */
281 if (stat(ctrlsock_name, &st) == 0)
282 {
283 /* verify that unix socket is not stale */
284 if (_ctrl_verify_unix_socket() == True)
285 {
286 _ctrl_is_slave = True;
287 return 1;
288 }
289 else
290 {
291 unlink(ctrlsock_name);
292 }
293 }
294
295 /* setup ctrl socket and start listening for connections */
296 if ((ctrlsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
297 {
298 perror("Error creating ctrl socket:");
299 exit(1);
300 }
301
302 /* bind and start listening on server socket */
303 memset(&saun, 0, sizeof(struct sockaddr_un));
304 saun.sun_family = AF_UNIX;
305 strncpy(saun.sun_path, ctrlsock_name, sizeof(saun.sun_path));
306 if (bind(ctrlsock, (struct sockaddr *) &saun, sizeof(struct sockaddr_un)) < 0)
307 {
308 perror("Error binding ctrl socket:");
309 exit(1);
310 }
311
312 if (listen(ctrlsock, 5) < 0)
313 {
314 perror("Error listening on socket:");
315 exit(1);
316 }
317
318 /* add ctrl cleanup func to exit hooks */
319 atexit(ctrl_cleanup);
320
321 return 0;
322}
323
324void
325ctrl_cleanup()
326{
327 if (ctrlsock)
328 {
329 close(ctrlsock);
330 unlink(ctrlsock_name);
331 }
332}
333
334RD_BOOL
335ctrl_is_slave()
336{
337 return _ctrl_is_slave;
338}
339
340
341void
342ctrl_add_fds(int *n, fd_set * rfds)
343{
344 _ctrl_slave_t *it;
345 if (ctrlsock == 0)
346 return;
347
348 FD_SET(ctrlsock, rfds);
349 *n = MAX(*n, ctrlsock);
350
351
352 /* add connected slaves to fd set */
353 it = _ctrl_slaves;
354 while (it)
355 {
356 FD_SET(it->sock, rfds);
357 *n = MAX(*n, it->sock);
358 it = it->next;
359 }
360}
361
362void
363ctrl_check_fds(fd_set * rfds, fd_set * wfds)
364{
365 int ns, res, offs;
366 struct sockaddr_un fsaun;
367 socklen_t fromlen;
368 _ctrl_slave_t *it;
369
370 if (ctrlsock == 0)
371 return;
372
373 memset(&fsaun, 0, sizeof(struct sockaddr_un));
374
375 /* check if we got any connections on server socket */
376 if (FD_ISSET(ctrlsock, rfds))
377 {
378 FD_CLR(ctrlsock, rfds);
379 fromlen = sizeof(fsaun);
380 ns = accept(ctrlsock, (struct sockaddr *) &fsaun, &fromlen);
381 if (ns < 0)
382 {
383 perror("server: accept()");
384 exit(1);
385 }
386
387 _ctrl_slave_new(ns);
388 return;
389 }
390
391 /* check if any of our slaves fds has data */
392 it = _ctrl_slaves;
393 while (it)
394 {
395 if (FD_ISSET(it->sock, rfds))
396 {
397 offs = strlen(it->linebuf);
398 res = recv(it->sock, it->linebuf + offs, CTRL_LINEBUF_SIZE - offs, 0);
399 FD_CLR(it->sock, rfds);
400
401 /* linebuffer full let's disconnect slave */
402 if (it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\0' &&
403 it->linebuf[CTRL_LINEBUF_SIZE - 1] != '\n')
404 {
405 _ctrl_slave_disconnect(it->sock);
406 break;
407 }
408
409 if (res > 0)
410 {
411 /* Check if we got full command line */
412 char *p;
413 if ((p = strchr(it->linebuf, '\n')) == NULL)
414 continue;
415
416 /* iterate over string and check against escaped \n */
417 while (p)
418 {
419 /* Check if newline is escaped */
420 if (p > it->linebuf && *(p - 1) != '\\')
421 break;
422 p = strchr(p + 1, '\n');
423 }
424
425 /* If we havent found an nonescaped \n we need more data */
426 if (p == NULL)
427 continue;
428
429 /* strip new linebuf and dispatch command */
430 *p = '\0';
431 _ctrl_dispatch_command(it);
432 memset(it->linebuf, 0, CTRL_LINEBUF_SIZE);
433 }
434 else
435 {
436 /* Peer disconnected or socket error */
437 _ctrl_slave_disconnect(it->sock);
438 break;
439 }
440 }
441 it = it->next;
442 }
443}
444
445#if HAVE_ICONV
446extern char g_codepage[16];
447#endif
448
449int
450ctrl_send_command(const char *cmd, const char *arg)
451{
452 FILE *fp;
453 struct sockaddr_un saun;
454 int s, len, index, ret;
455 char data[CTRL_LINEBUF_SIZE], tmp[CTRL_LINEBUF_SIZE];
456 char result[CTRL_RESULT_SIZE], c, *escaped;
457
458 escaped = NULL;
459
460 if (!_ctrl_is_slave)
461 return -1;
462
463 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
464 {
465 perror("Error creating ctrl client socket: socket()");
466 exit(1);
467 }
468
469 memset(&saun, 0, sizeof(struct sockaddr_un));
470 saun.sun_family = AF_UNIX;
471 strcpy(saun.sun_path, ctrlsock_name);
472 len = sizeof(saun.sun_family) + strlen(saun.sun_path);
473
474 if (connect(s, (struct sockaddr *) &saun, len) < 0)
475 {
476 perror("Error connecting to ctrl socket: connect()");
477 exit(1);
478 }
479
480 /* Bundle cmd and argument into string, convert to UTF-8 if needed */
481 snprintf(data, CTRL_LINEBUF_SIZE, "%s %s", cmd, arg);
482 ret = utils_locale_to_utf8(data, strlen(data), tmp, CTRL_LINEBUF_SIZE - 1);
483
484 if (ret != 0)
485 goto bail_out;
486
487 /* escape the utf-8 string */
488 escaped = utils_string_escape(tmp);
489 if ((strlen(escaped) + 1) > CTRL_LINEBUF_SIZE - 1)
490 goto bail_out;
491
492 /* send escaped utf-8 command to master */
493 send(s, escaped, strlen(escaped), 0);
494 send(s, "\n", 1, 0);
495
496 /* read result from master */
497 fp = fdopen(s, "r");
498 index = 0;
499 while ((c = fgetc(fp)) != EOF && index < CTRL_RESULT_SIZE && c != '\n')
500 {
501 result[index] = c;
502 index++;
503 }
504 result[index - 1] = '\0';
505
506 if (strncmp(result, "ERROR ", 6) == 0)
507 {
508 if (sscanf(result, "ERROR %d", &ret) != 1)
509 ret = -1;
510 }
511
512 bail_out:
513 xfree(escaped);
514 shutdown(s, SHUT_RDWR);
515 close(s);
516
517 return ret;
518}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette