vfs: check userland buffers before reading them.
[haiku.git] / src / apps / remotedesktop / RemoteDesktop.cpp
blob0ed18d8d5ec4f656847083d2f7f759ae01149eb2
1 /*
2 * Copyright 2009-2017, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 */
9 #include <Application.h>
10 #include <FindDirectory.h>
11 #include <Path.h>
12 #include <Screen.h>
13 #include <Window.h>
15 #include "RemoteView.h"
17 #include <new>
18 #include <signal.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/wait.h>
22 #include <unistd.h>
25 void
26 print_usage(const char *app)
28 printf("usage:\t%s <host> [-p <port>] [-w <width>] [-h <height>]\n", app);
29 printf("usage:\t%s <user@host> -s [<sshPort>] [-p <port>] [-w <width>]"
30 " [-h <height>] [-c <command>]\n", app);
31 printf("\t%s --help\n\n", app);
33 printf("Connect to & run applications from a different computer\n\n");
34 printf("Arguments available for use:\n\n");
35 printf("\t-p\t\tspecify the port to communicate on (default 10900)\n");
36 printf("\t-c\t\tsend a command to the other computer (default Terminal)\n");
37 printf("\t-s\t\tuse SSH, optionally specify the SSH port to use (22)\n");
38 printf("\t-w\t\tmake the virtual desktop use the specified width\n");
39 printf("\t-h\t\tmake the virtual desktop use the specified height\n");
40 printf("\nIf no width and height are specified, the window is opened with"
41 " the size of the the local screen.\n");
45 int
46 main(int argc, char *argv[])
48 if (argc < 2 || strcmp(argv[1], "--help") == 0) {
49 print_usage(argv[0]);
50 return 1;
53 uint16 port = 10900;
54 uint16 sshPort = 22;
55 int32 width = -1;
56 int32 height = -1;
57 bool useSSH = false;
58 const char *command = NULL;
59 const char *host = argv[1];
61 for (int32 i = 2; i < argc; i++) {
62 if (strcmp(argv[i], "-p") == 0) {
63 if (argc < i + 1 || sscanf(argv[i + 1], "%" B_SCNu16, &port)
64 != 1) {
65 print_usage(argv[0]);
66 return 2;
69 i++;
70 continue;
73 if (strcmp(argv[i], "-w") == 0) {
74 if (argc < i + 1 || sscanf(argv[i + 1], "%" B_SCNd32, &width) != 1)
76 print_usage(argv[0]);
77 return 2;
80 i++;
81 continue;
84 if (strcmp(argv[i], "-h") == 0) {
85 if (argc < i + 1 || sscanf(argv[i + 1], "%" B_SCNd32, &height) != 1)
87 print_usage(argv[0]);
88 return 2;
91 i++;
92 continue;
95 if (strcmp(argv[i], "-s") == 0) {
96 if (argc >= i + 1
97 && sscanf(argv[i + 1], "%" B_SCNu16, &sshPort) == 1) {
98 i++;
101 useSSH = true;
102 continue;
105 if (strcmp(argv[i], "-c") == 0) {
106 if (argc < i + 1) {
107 print_usage(argv[0]);
108 return 2;
111 i++;
112 command = argv[i];
113 continue;
116 print_usage(argv[0]);
117 return 2;
120 if (command != NULL && !useSSH) {
121 print_usage(argv[0]);
122 return 2;
125 pid_t sshPID = -1;
126 if (useSSH) {
127 BPath terminalPath;
128 if (command == NULL) {
129 if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath)
130 != B_OK) {
131 printf("failed to determine system-apps directory\n");
132 return 3;
134 if (terminalPath.Append("Terminal") != B_OK) {
135 printf("failed to append to system-apps path\n");
136 return 3;
138 command = terminalPath.Path();
141 char shellCommand[4096];
142 snprintf(shellCommand, sizeof(shellCommand),
143 "echo connected; export TARGET_SCREEN=%" B_PRIu16 "; %s\n", port,
144 command);
146 int pipes[4];
147 if (pipe(&pipes[0]) != 0 || pipe(&pipes[2]) != 0) {
148 printf("failed to create redirection pipes\n");
149 return 3;
152 sshPID = fork();
153 if (sshPID < 0) {
154 printf("failed to fork ssh process\n");
155 return 3;
158 if (sshPID == 0) {
159 // child code, redirect std* and execute ssh
160 close(STDOUT_FILENO);
161 close(STDIN_FILENO);
162 dup2(pipes[1], STDOUT_FILENO);
163 dup2(pipes[1], STDERR_FILENO);
164 dup2(pipes[2], STDIN_FILENO);
165 for (int32 i = 0; i < 4; i++)
166 close(pipes[i]);
168 char localRedirect[50];
169 sprintf(localRedirect, "localhost:%" B_PRIu16 ":localhost:%"
170 B_PRIu16, port, port);
172 char portNumber[10];
173 sprintf(portNumber, "%" B_PRIu16, sshPort);
175 int result = execl("ssh", "-C", "-L", localRedirect,
176 "-p", portNumber, "-o", "ExitOnForwardFailure=yes", host,
177 shellCommand, NULL);
179 // we don't get here unless there was an error in executing
180 printf("failed to execute ssh process in child\n");
181 return result;
182 } else {
183 close(pipes[1]);
184 close(pipes[2]);
186 char buffer[10];
187 read(pipes[0], buffer, sizeof(buffer));
188 // block until connected/error message from ssh
190 host = "localhost";
194 BApplication app("application/x-vnd.Haiku-RemoteDesktop");
195 BRect windowFrame = BRect(0, 0, width - 1, height - 1);
196 if (!windowFrame.IsValid()) {
197 BScreen screen;
198 windowFrame = screen.Frame();
201 BWindow *window = new(std::nothrow) BWindow(windowFrame, "RemoteDesktop",
202 B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE);
204 if (window == NULL) {
205 printf("no memory to allocate window\n");
206 return 4;
209 RemoteView *view = new(std::nothrow) RemoteView(window->Bounds(), host,
210 port);
211 if (view == NULL) {
212 printf("no memory to allocate remote view\n");
213 return 4;
216 status_t init = view->InitCheck();
217 if (init != B_OK) {
218 printf("initialization of remote view failed: %s\n", strerror(init));
219 delete view;
220 return 5;
223 window->AddChild(view);
224 view->MakeFocus();
225 window->Show();
226 app.Run();
228 if (sshPID >= 0)
229 kill(sshPID, SIGHUP);
231 return 0;