1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include "config.h"
21 
22 #include "log.h"
23 #include "move-fd.h"
24 #include "proc.h"
25 #include "proc-map.h"
26 
27 #include <guacamole/client.h>
28 #include <guacamole/error.h>
29 #include <guacamole/parser.h>
30 #include <guacamole/plugin.h>
31 #include <guacamole/protocol.h>
32 #include <guacamole/socket.h>
33 #include <guacamole/user.h>
34 
35 #include <errno.h>
36 #include <pthread.h>
37 #include <signal.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <sys/time.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <sys/wait.h>
45 
46 /**
47  * Parameters for the user thread.
48  */
49 typedef struct guacd_user_thread_params {
50 
51     /**
52      * The process being joined.
53      */
54     guacd_proc* proc;
55 
56     /**
57      * The file descriptor of the joining user's socket.
58      */
59     int fd;
60 
61     /**
62      * Whether the joining user is the connection owner.
63      */
64     int owner;
65 
66 } guacd_user_thread_params;
67 
68 /**
69  * Handles a user's entire connection and socket lifecycle.
70  *
71  * @param data
72  *     A pointer to a guacd_user_thread_params structure describing the user's
73  *     associated file descriptor, whether that user is the connection owner
74  *     (the first person to join), as well as the process associated with the
75  *     connection being joined.
76  *
77  * @return
78  *     Always NULL.
79  */
guacd_user_thread(void * data)80 static void* guacd_user_thread(void* data) {
81 
82     guacd_user_thread_params* params = (guacd_user_thread_params*) data;
83     guacd_proc* proc = params->proc;
84     guac_client* client = proc->client;
85 
86     /* Get guac_socket for user's file descriptor */
87     guac_socket* socket = guac_socket_open(params->fd);
88     if (socket == NULL)
89         return NULL;
90 
91     /* Create skeleton user */
92     guac_user* user = guac_user_alloc();
93     user->socket = socket;
94     user->client = client;
95     user->owner  = params->owner;
96 
97     /* Handle user connection from handshake until disconnect/completion */
98     guac_user_handle_connection(user, GUACD_USEC_TIMEOUT);
99 
100     /* Stop client and prevent future users if all users are disconnected */
101     if (client->connected_users == 0) {
102         guacd_log(GUAC_LOG_INFO, "Last user of connection \"%s\" disconnected", client->connection_id);
103         guacd_proc_stop(proc);
104     }
105 
106     /* Clean up */
107     guac_socket_free(socket);
108     guac_user_free(user);
109     free(params);
110 
111     return NULL;
112 
113 }
114 
115 /**
116  * Begins a new user connection under a given process, using the given file
117  * descriptor. The connection will be managed by a separate and detached thread
118  * which is started by this function.
119  *
120  * @param proc
121  *     The process that the user is being added to.
122  *
123  * @param fd
124  *     The file descriptor associated with the user's network connection to
125  *     guacd.
126  *
127  * @param owner
128  *     Non-zero if the user is the owner of the connection being joined (they
129  *     are the first user to join), or zero otherwise.
130  */
guacd_proc_add_user(guacd_proc * proc,int fd,int owner)131 static void guacd_proc_add_user(guacd_proc* proc, int fd, int owner) {
132 
133     guacd_user_thread_params* params = malloc(sizeof(guacd_user_thread_params));
134     params->proc = proc;
135     params->fd = fd;
136     params->owner = owner;
137 
138     /* Start user thread */
139     pthread_t user_thread;
140     pthread_create(&user_thread, NULL, guacd_user_thread, params);
141     pthread_detach(user_thread);
142 
143 }
144 
145 /**
146  * Forcibly kills all processes within the current process group, including the
147  * current process and all child processes. This function is only safe to call
148  * if the process group ID has been correctly set. Calling this function within
149  * a process which does not have a PGID separate from the main guacd process
150  * can result in guacd itself being terminated.
151  */
guacd_kill_current_proc_group()152 static void guacd_kill_current_proc_group() {
153 
154     /* Forcibly kill all children within process group */
155     if (kill(0, SIGKILL))
156         guacd_log(GUAC_LOG_WARNING, "Unable to forcibly terminate "
157                 "client process: %s ", strerror(errno));
158 
159 }
160 
161 /**
162  * The current status of a background attempt to free a guac_client instance.
163  */
164 typedef struct guacd_client_free {
165 
166     /**
167      * The guac_client instance being freed.
168      */
169     guac_client* client;
170 
171     /**
172      * The condition which is signalled whenever changes are made to the
173      * completed flag. The completed flag only changes from zero (not yet
174      * freed) to non-zero (successfully freed).
175      */
176     pthread_cond_t completed_cond;
177 
178     /**
179      * Mutex which must be acquired before any changes are made to the
180      * completed flag.
181      */
182     pthread_mutex_t completed_mutex;
183 
184     /**
185      * Whether the guac_client has been successfully freed. Initially, this
186      * will be zero, indicating that the free operation has not yet been
187      * attempted. If the client is eventually successfully freed, this will be
188      * set to a non-zero value. Changes to this flag are signalled through
189      * the completed_cond condition.
190      */
191     int completed;
192 
193 } guacd_client_free;
194 
195 /**
196  * Thread which frees a given guac_client instance in the background. If the
197  * free operation succeeds, a flag is set on the provided structure, and the
198  * change in that flag is signalled with a pthread condition.
199  *
200  * At the time this function is provided to a pthread_create() call, the
201  * completed flag of the associated guacd_client_free structure MUST be
202  * initialized to zero, the pthread mutex and condition MUST both be
203  * initialized, and the client pointer must point to the guac_client being
204  * freed.
205  *
206  * @param data
207  *     A pointer to a guacd_client_free structure describing the free
208  *     operation.
209  *
210  * @return
211  *     Always NULL.
212  */
guacd_client_free_thread(void * data)213 static void* guacd_client_free_thread(void* data) {
214 
215     guacd_client_free* free_operation = (guacd_client_free*) data;
216 
217     /* Attempt to free client (this may never return if the client is
218      * malfunctioning) */
219     guac_client_free(free_operation->client);
220 
221     /* Signal that the client was successfully freed */
222     pthread_mutex_lock(&free_operation->completed_mutex);
223     free_operation->completed = 1;
224     pthread_cond_broadcast(&free_operation->completed_cond);
225     pthread_mutex_unlock(&free_operation->completed_mutex);
226 
227     return NULL;
228 
229 }
230 
231 /**
232  * Attempts to free the given guac_client, restricting the time taken by the
233  * free handler of the guac_client to a finite number of seconds. If the free
234  * handler does not complete within the time alotted, this function returns
235  * and the intended free operation is left in an undefined state.
236  *
237  * @param client
238  *     The guac_client instance to free.
239  *
240  * @param timeout
241  *     The maximum amount of time to wait for the guac_client to be freed,
242  *     in seconds.
243  *
244  * @return
245  *     Zero if the guac_client was successfully freed within the time alotted,
246  *     non-zero otherwise.
247  */
guacd_timed_client_free(guac_client * client,int timeout)248 static int guacd_timed_client_free(guac_client* client, int timeout) {
249 
250     pthread_t client_free_thread;
251 
252     guacd_client_free free_operation = {
253         .client = client,
254         .completed_cond = PTHREAD_COND_INITIALIZER,
255         .completed_mutex = PTHREAD_MUTEX_INITIALIZER,
256         .completed = 0
257     };
258 
259     /* Get current time */
260     struct timeval current_time;
261     if (gettimeofday(&current_time, NULL))
262         return 1;
263 
264     /* Calculate exact time that the free operation MUST complete by */
265     struct timespec deadline = {
266         .tv_sec  = current_time.tv_sec + timeout,
267         .tv_nsec = current_time.tv_usec * 1000
268     };
269 
270     /* The mutex associated with the pthread conditional and flag MUST be
271      * acquired before attempting to wait for the condition */
272     if (pthread_mutex_lock(&free_operation.completed_mutex))
273         return 1;
274 
275     /* Free the client in a separate thread, so we can time the free operation */
276     if (!pthread_create(&client_free_thread, NULL,
277                 guacd_client_free_thread, &free_operation)) {
278 
279         /* Wait a finite amount of time for the free operation to finish */
280         (void) pthread_cond_timedwait(&free_operation.completed_cond,
281                     &free_operation.completed_mutex, &deadline);
282     }
283 
284     (void) pthread_mutex_unlock(&free_operation.completed_mutex);
285 
286     /* Return status of free operation */
287     return !free_operation.completed;
288 }
289 
290 /**
291  * Starts protocol-specific handling on the given process by loading the client
292  * plugin for that protocol. This function does NOT return. It initializes the
293  * process with protocol-specific handlers and then runs until the guacd_proc's
294  * fd_socket is closed, adding any file descriptors received along fd_socket as
295  * new users.
296  *
297  * @param proc
298  *     The process that any new users received along fd_socket should be added
299  *     to (after the process has been initialized for the given protocol).
300  *
301  * @param protocol
302  *     The protocol to initialize the given process for.
303  */
guacd_exec_proc(guacd_proc * proc,const char * protocol)304 static void guacd_exec_proc(guacd_proc* proc, const char* protocol) {
305 
306     int result = 1;
307 
308     /* Set process group ID to match PID */
309     if (setpgid(0, 0)) {
310         guacd_log(GUAC_LOG_ERROR, "Cannot set PGID for connection process: %s",
311                 strerror(errno));
312         goto cleanup_process;
313     }
314 
315     /* Init client for selected protocol */
316     guac_client* client = proc->client;
317     if (guac_client_load_plugin(client, protocol)) {
318 
319         /* Log error */
320         if (guac_error == GUAC_STATUS_NOT_FOUND)
321             guacd_log(GUAC_LOG_WARNING,
322                     "Support for protocol \"%s\" is not installed", protocol);
323         else
324             guacd_log_guac_error(GUAC_LOG_ERROR,
325                     "Unable to load client plugin");
326 
327         goto cleanup_client;
328     }
329 
330     /* The first file descriptor is the owner */
331     int owner = 1;
332 
333     /* Enable keep alive on the broadcast socket */
334     guac_socket_require_keep_alive(client->socket);
335 
336     /* Add each received file descriptor as a new user */
337     int received_fd;
338     while ((received_fd = guacd_recv_fd(proc->fd_socket)) != -1) {
339 
340         guacd_proc_add_user(proc, received_fd, owner);
341 
342         /* Future file descriptors are not owners */
343         owner = 0;
344 
345     }
346 
347 cleanup_client:
348 
349     /* Request client to stop/disconnect */
350     guac_client_stop(client);
351 
352     /* Attempt to free client cleanly */
353     guacd_log(GUAC_LOG_DEBUG, "Requesting termination of client...");
354     result = guacd_timed_client_free(client, GUACD_CLIENT_FREE_TIMEOUT);
355 
356     /* If client was unable to be freed, warn and forcibly kill */
357     if (result) {
358         guacd_log(GUAC_LOG_WARNING, "Client did not terminate in a timely "
359                 "manner. Forcibly terminating client and any child "
360                 "processes.");
361         guacd_kill_current_proc_group();
362     }
363     else
364         guacd_log(GUAC_LOG_DEBUG, "Client terminated successfully.");
365 
366     /* Verify whether children were all properly reaped */
367     pid_t child_pid;
368     while ((child_pid = waitpid(0, NULL, WNOHANG)) > 0) {
369         guacd_log(GUAC_LOG_DEBUG, "Automatically reaped unreaped "
370                 "(zombie) child process with PID %i.", child_pid);
371     }
372 
373     /* If running children remain, warn and forcibly kill */
374     if (child_pid == 0) {
375         guacd_log(GUAC_LOG_WARNING, "Client reported successful termination, "
376                 "but child processes remain. Forcibly terminating client and "
377                 "child processes.");
378         guacd_kill_current_proc_group();
379     }
380 
381 cleanup_process:
382 
383     /* Free up all internal resources outside the client */
384     close(proc->fd_socket);
385     free(proc);
386 
387     exit(result);
388 
389 }
390 
guacd_create_proc(const char * protocol)391 guacd_proc* guacd_create_proc(const char* protocol) {
392 
393     int sockets[2];
394 
395     /* Open UNIX socket pair */
396     if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0) {
397         guacd_log(GUAC_LOG_ERROR, "Error opening socket pair: %s", strerror(errno));
398         return NULL;
399     }
400 
401     int parent_socket = sockets[0];
402     int child_socket = sockets[1];
403 
404     /* Allocate process */
405     guacd_proc* proc = calloc(1, sizeof(guacd_proc));
406     if (proc == NULL) {
407         close(parent_socket);
408         close(child_socket);
409         return NULL;
410     }
411 
412     /* Associate new client */
413     proc->client = guac_client_alloc();
414     if (proc->client == NULL) {
415         guacd_log_guac_error(GUAC_LOG_ERROR, "Unable to create client");
416         close(parent_socket);
417         close(child_socket);
418         free(proc);
419         return NULL;
420     }
421 
422     /* Init logging */
423     proc->client->log_handler = guacd_client_log;
424 
425     /* Fork */
426     proc->pid = fork();
427     if (proc->pid < 0) {
428         guacd_log(GUAC_LOG_ERROR, "Cannot fork child process: %s", strerror(errno));
429         close(parent_socket);
430         close(child_socket);
431         guac_client_free(proc->client);
432         free(proc);
433         return NULL;
434     }
435 
436     /* Child */
437     else if (proc->pid == 0) {
438 
439         /* Communicate with parent */
440         proc->fd_socket = parent_socket;
441         close(child_socket);
442 
443         /* Start protocol-specific handling */
444         guacd_exec_proc(proc, protocol);
445 
446     }
447 
448     /* Parent */
449     else {
450 
451         /* Communicate with child */
452         proc->fd_socket = child_socket;
453         close(parent_socket);
454 
455     }
456 
457     return proc;
458 
459 }
460 
guacd_proc_stop(guacd_proc * proc)461 void guacd_proc_stop(guacd_proc* proc) {
462 
463     /* Signal client to stop */
464     guac_client_stop(proc->client);
465 
466     /* Shutdown socket - in-progress recvmsg() will not fail otherwise */
467     if (shutdown(proc->fd_socket, SHUT_RDWR) == -1)
468         guacd_log(GUAC_LOG_ERROR, "Unable to shutdown internal socket for "
469                 "connection %s. Corresponding process may remain running but "
470                 "inactive.", proc->client->connection_id);
471 
472     /* Clean up our end of the socket */
473     close(proc->fd_socket);
474 
475 }
476 
477