GUACAMOLE-623: Add base skeleton for Kubernetes protocol support.

This commit is contained in:
Michael Jumper 2018-09-09 20:03:40 -07:00
parent 54fda21366
commit b8bd0e4c6a
17 changed files with 1572 additions and 8 deletions

View File

@ -52,6 +52,10 @@ if ENABLE_PULSE
SUBDIRS += src/pulse
endif
if ENABLE_KUBERNETES
SUBDIRS += src/protocols/kubernetes
endif
if ENABLE_RDP
SUBDIRS += src/protocols/rdp
endif

View File

@ -1172,6 +1172,46 @@ fi
AM_CONDITIONAL([ENABLE_WEBP], [test "x${have_webp}" = "xyes"])
AC_SUBST(WEBP_LIBS)
#
# libwebsockets
#
have_libwebsockets=disabled
WEBSOCKETS_LIBS=
AC_ARG_WITH([websockets],
[AS_HELP_STRING([--with-websockets],
[support WebSockets @<:@default=check@:>@])],
[],
[with_websockets=check])
if test "x$with_websockets" != "xno"
then
have_libwebsockets=yes
AC_CHECK_LIB([websockets],
[lws_create_context],
[WEBSOCKETS_LIBS="$WEBSOCKETS_LIBS -lwebsockets"],
[have_libwebsockets=no])
fi
AM_CONDITIONAL([ENABLE_WEBSOCKETS],
[test "x${have_libwebsockets}" = "xyes"])
AC_SUBST(WEBSOCKETS_LIBS)
#
# Kubernetes
#
AC_ARG_ENABLE([kubernetes],
[AS_HELP_STRING([--disable-kubernetes],
[do not build support for attaching to Kubernetes pods])],
[],
[enable_kubernetes=yes])
AM_CONDITIONAL([ENABLE_KUBERNETES], [test "x${enable_kubernetes}" = "xyes" \
-a "x${have_libwebsockets}" = "xyes" \
-a "x${have_terminal}" = "xyes"])
#
# guacd
#
@ -1230,6 +1270,7 @@ AC_CONFIG_FILES([Makefile
src/guaclog/Makefile
src/guaclog/man/guaclog.1
src/pulse/Makefile
src/protocols/kubernetes/Makefile
src/protocols/rdp/Makefile
src/protocols/ssh/Makefile
src/protocols/telnet/Makefile
@ -1240,6 +1281,7 @@ AC_OUTPUT
# Protocol build status
#
AM_COND_IF([ENABLE_KUBERNETES], [build_kubernetes=yes], [build_kubernetes=no])
AM_COND_IF([ENABLE_RDP], [build_rdp=yes], [build_rdp=no])
AM_COND_IF([ENABLE_SSH], [build_ssh=yes], [build_ssh=no])
AM_COND_IF([ENABLE_TELNET], [build_telnet=yes], [build_telnet=no])
@ -1287,15 +1329,17 @@ $PACKAGE_NAME version $PACKAGE_VERSION
libVNCServer ........ ${have_libvncserver}
libvorbis ........... ${have_vorbis}
libpulse ............ ${have_pulse}
libwebsockets ....... ${have_websockets}
libwebp ............. ${have_webp}
wsock32 ............. ${have_winsock}
Protocol support:
RDP ....... ${build_rdp}
SSH ....... ${build_ssh}
Telnet .... ${build_telnet}
VNC ....... ${build_vnc}
Kubernetes .... ${build_kubernetes}
RDP ........... ${build_rdp}
SSH ........... ${build_ssh}
Telnet ........ ${build_telnet}
VNC ........... ${build_vnc}
Services / tools:

View File

@ -0,0 +1,57 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
AUTOMAKE_OPTIONS = foreign
ACLOCAL_AMFLAGS = -I m4
lib_LTLIBRARIES = libguac-client-kubernetes.la
libguac_client_kubernetes_la_SOURCES = \
client.c \
clipboard.c \
input.c \
pipe.c \
settings.c \
kubernetes.c \
user.c
noinst_HEADERS = \
client.h \
clipboard.h \
input.h \
pipe.h \
settings.h \
kubernetes.h \
user.h
libguac_client_kubernetes_la_CFLAGS = \
-Werror -Wall -Iinclude \
@LIBGUAC_INCLUDE@ \
@TERMINAL_INCLUDE@
libguac_client_kubernetes_la_LIBADD = \
@COMMON_LTLIB@ \
@LIBGUAC_LTLIB@ \
@TERMINAL_LTLIB@
libguac_client_kubernetes_la_LDFLAGS = \
-version-info 0:0:0 \
@PTHREAD_LIBS@ \
@WEBSOCKETS_LIBS@

View File

@ -0,0 +1,91 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "client.h"
#include "common/recording.h"
#include "kubernetes.h"
#include "settings.h"
#include "terminal/terminal.h"
#include "user.h"
#include <langinfo.h>
#include <locale.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <guacamole/client.h>
int guac_client_init(guac_client* client) {
/* Set client args */
client->args = GUAC_KUBERNETES_CLIENT_ARGS;
/* Allocate client instance data */
guac_kubernetes_client* kubernetes_client = calloc(1, sizeof(guac_kubernetes_client));
client->data = kubernetes_client;
/* Init clipboard */
kubernetes_client->clipboard = guac_common_clipboard_alloc(GUAC_KUBERNETES_CLIPBOARD_MAX_LENGTH);
/* Set handlers */
client->join_handler = guac_kubernetes_user_join_handler;
client->free_handler = guac_kubernetes_client_free_handler;
/* Set locale and warn if not UTF-8 */
setlocale(LC_CTYPE, "");
if (strcmp(nl_langinfo(CODESET), "UTF-8") != 0) {
guac_client_log(client, GUAC_LOG_INFO,
"Current locale does not use UTF-8. Some characters may "
"not render correctly.");
}
/* Success */
return 0;
}
int guac_kubernetes_client_free_handler(guac_client* client) {
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;
/* Clean up recording, if in progress */
if (kubernetes_client->recording != NULL)
guac_common_recording_free(kubernetes_client->recording);
/* Kill terminal */
guac_terminal_free(kubernetes_client->term);
/* TODO: Wait for and free WebSocket session, if connected */
/*if (kubernetes_client->websocket != NULL) {
pthread_join(kubernetes_client->client_thread, NULL);
}*/
/* Free settings */
if (kubernetes_client->settings != NULL)
guac_kubernetes_settings_free(kubernetes_client->settings);
guac_common_clipboard_free(kubernetes_client->clipboard);
free(kubernetes_client);
return 0;
}

View File

@ -0,0 +1,41 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUAC_KUBERNETES_CLIENT_H
#define GUAC_KUBERNETES_CLIENT_H
#include "config.h"
#include "terminal/terminal.h"
#include <pthread.h>
#include <sys/types.h>
/**
* The maximum number of bytes to allow within the clipboard.
*/
#define GUAC_KUBERNETES_CLIPBOARD_MAX_LENGTH 262144
/**
* Free handler. Required by libguac and called when the guac_client is
* disconnected and must be cleaned up.
*/
guac_client_free_handler guac_kubernetes_client_free_handler;
#endif

View File

@ -0,0 +1,67 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "clipboard.h"
#include "common/clipboard.h"
#include "kubernetes.h"
#include "terminal/terminal.h"
#include <guacamole/client.h>
#include <guacamole/stream.h>
#include <guacamole/user.h>
int guac_kubernetes_clipboard_handler(guac_user* user, guac_stream* stream,
char* mimetype) {
guac_client* client = user->client;
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;
/* Clear clipboard and prepare for new data */
guac_common_clipboard_reset(kubernetes_client->clipboard, mimetype);
/* Set handlers for clipboard stream */
stream->blob_handler = guac_kubernetes_clipboard_blob_handler;
stream->end_handler = guac_kubernetes_clipboard_end_handler;
return 0;
}
int guac_kubernetes_clipboard_blob_handler(guac_user* user,
guac_stream* stream, void* data, int length) {
guac_client* client = user->client;
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;
/* Append new data */
guac_common_clipboard_append(kubernetes_client->clipboard, data, length);
return 0;
}
int guac_kubernetes_clipboard_end_handler(guac_user* user,
guac_stream* stream) {
/* Nothing to do - clipboard is implemented within client */
return 0;
}

View File

@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUAC_KUBERNETES_CLIPBOARD_H
#define GUAC_KUBERNETES_CLIPBOARD_H
#include "config.h"
#include <guacamole/user.h>
/**
* Handler for inbound clipboard streams.
*/
guac_user_clipboard_handler guac_kubernetes_clipboard_handler;
/**
* Handler for data received along clipboard streams.
*/
guac_user_blob_handler guac_kubernetes_clipboard_blob_handler;
/**
* Handler for end-of-stream related to clipboard.
*/
guac_user_end_handler guac_kubernetes_clipboard_end_handler;
#endif

View File

@ -0,0 +1,95 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "common/recording.h"
#include "kubernetes.h"
#include "input.h"
#include "terminal/terminal.h"
#include <guacamole/client.h>
#include <guacamole/user.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int guac_kubernetes_user_mouse_handler(guac_user* user,
int x, int y, int mask) {
guac_client* client = user->client;
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;
/* Skip if terminal not yet ready */
guac_terminal* term = kubernetes_client->term;
if (term == NULL)
return 0;
/* Report mouse position within recording */
if (kubernetes_client->recording != NULL)
guac_common_recording_report_mouse(kubernetes_client->recording, x, y,
mask);
guac_terminal_send_mouse(term, user, x, y, mask);
return 0;
}
int guac_kubernetes_user_key_handler(guac_user* user, int keysym, int pressed) {
guac_client* client = user->client;
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;
/* Report key state within recording */
if (kubernetes_client->recording != NULL)
guac_common_recording_report_key(kubernetes_client->recording,
keysym, pressed);
/* Skip if terminal not yet ready */
guac_terminal* term = kubernetes_client->term;
if (term == NULL)
return 0;
guac_terminal_send_key(term, keysym, pressed);
return 0;
}
int guac_kubernetes_user_size_handler(guac_user* user, int width, int height) {
/* Get terminal */
guac_client* client = user->client;
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;
/* Skip if terminal not yet ready */
guac_terminal* terminal = kubernetes_client->term;
if (terminal == NULL)
return 0;
/* Resize terminal */
guac_terminal_resize(terminal, width, height);
/* TODO: Update Kubernetes terminal window size if connected */
return 0;
}

View File

@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUAC_KUBERNETES_INPUT_H
#define GUAC_KUBERNETES_INPUT_H
#include "config.h"
#include <guacamole/user.h>
/**
* Handler for key events. Required by libguac and called whenever key events
* are received.
*/
guac_user_key_handler guac_kubernetes_user_key_handler;
/**
* Handler for mouse events. Required by libguac and called whenever mouse
* events are received.
*/
guac_user_mouse_handler guac_kubernetes_user_mouse_handler;
/**
* Handler for size events. Required by libguac and called whenever the remote
* display (window) is resized.
*/
guac_user_size_handler guac_kubernetes_user_size_handler;
#endif

View File

@ -0,0 +1,136 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "common/recording.h"
#include "kubernetes.h"
#include "terminal/terminal.h"
#include <guacamole/client.h>
#include <guacamole/protocol.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <poll.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
/**
* Input thread, started by the main Kubernetes client thread. This thread
* continuously reads from the terminal's STDIN and transfers all read
* data to the Kubernetes connection.
*
* @param data
* The current guac_client instance.
*
* @return
* Always NULL.
*/
static void* guac_kubernetes_input_thread(void* data) {
guac_client* client = (guac_client*) data;
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;
char buffer[8192];
int bytes_read;
/* Write all data read */
while ((bytes_read = guac_terminal_read_stdin(kubernetes_client->term, buffer, sizeof(buffer))) > 0) {
/* TODO: Send to Kubernetes */
guac_terminal_write(kubernetes_client->term, buffer, bytes_read);
}
return NULL;
}
void* guac_kubernetes_client_thread(void* data) {
guac_client* client = (guac_client*) data;
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;
guac_kubernetes_settings* settings = kubernetes_client->settings;
pthread_t input_thread;
/* Set up screen recording, if requested */
if (settings->recording_path != NULL) {
kubernetes_client->recording = guac_common_recording_create(client,
settings->recording_path,
settings->recording_name,
settings->create_recording_path,
!settings->recording_exclude_output,
!settings->recording_exclude_mouse,
settings->recording_include_keys);
}
/* Create terminal */
kubernetes_client->term = guac_terminal_create(client,
kubernetes_client->clipboard,
settings->max_scrollback, settings->font_name, settings->font_size,
settings->resolution, settings->width, settings->height,
settings->color_scheme, settings->backspace);
/* Fail if terminal init failed */
if (kubernetes_client->term == NULL) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Terminal initialization failed");
return NULL;
}
/* Set up typescript, if requested */
if (settings->typescript_path != NULL) {
guac_terminal_create_typescript(kubernetes_client->term,
settings->typescript_path,
settings->typescript_name,
settings->create_typescript_path);
}
/* TODO: Open WebSocket connection to Kubernetes */
/* Logged in */
guac_client_log(client, GUAC_LOG_INFO,
"Kubernetes connection successful.");
/* Start input thread */
if (pthread_create(&(input_thread), NULL, guac_kubernetes_input_thread, (void*) client)) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR, "Unable to start input thread");
return NULL;
}
/* TODO: While data available, write to terminal */
/* Kill client and Wait for input thread to die */
guac_client_stop(client);
pthread_join(input_thread, NULL);
guac_client_log(client, GUAC_LOG_INFO, "Kubernetes connection ended.");
return NULL;
}

View File

@ -0,0 +1,71 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUAC_KUBERNETES_H
#define GUAC_KUBERNETES_H
#include "config.h"
#include "common/clipboard.h"
#include "common/recording.h"
#include "settings.h"
#include "terminal/terminal.h"
#include <stdint.h>
/**
* Kubernetes-specific client data.
*/
typedef struct guac_kubernetes_client {
/**
* Kubernetes connection settings.
*/
guac_kubernetes_settings* settings;
/**
* The Kubernetes client thread.
*/
pthread_t client_thread;
/**
* The current clipboard contents.
*/
guac_common_clipboard* clipboard;
/**
* The terminal which will render all output from the Kubernetes pod.
*/
guac_terminal* term;
/**
* The in-progress session recording, or NULL if no recording is in
* progress.
*/
guac_common_recording* recording;
} guac_kubernetes_client;
/**
* Main Kubernetes client thread, handling transfer of STDOUT/STDERR of an
* attached Kubernetes pod to STDOUT of the terminal.
*/
void* guac_kubernetes_client_thread(void* data);
#endif

View File

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "kubernetes.h"
#include "pipe.h"
#include "terminal/terminal.h"
#include <guacamole/protocol.h>
#include <guacamole/socket.h>
#include <guacamole/user.h>
#include <string.h>
int guac_kubernetes_pipe_handler(guac_user* user, guac_stream* stream,
char* mimetype, char* name) {
guac_client* client = user->client;
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;
/* Redirect STDIN if pipe has required name */
if (strcmp(name, GUAC_KUBERNETES_STDIN_PIPE_NAME) == 0) {
guac_terminal_send_stream(kubernetes_client->term, user, stream);
return 0;
}
/* No other inbound pipe streams are supported */
guac_protocol_send_ack(user->socket, stream, "No such input stream.",
GUAC_PROTOCOL_STATUS_RESOURCE_NOT_FOUND);
guac_socket_flush(user->socket);
return 0;
}

View File

@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUAC_KUBERNETES_PIPE_H
#define GUAC_KUBERNETES_PIPE_H
#include "config.h"
#include <guacamole/user.h>
/**
* The name reserved for the inbound pipe stream which forces the terminal
* emulator's STDIN to be received from the pipe.
*/
#define GUAC_KUBERNETES_STDIN_PIPE_NAME "STDIN"
/**
* Handles an incoming stream from a Guacamole "pipe" instruction. If the pipe
* is named "STDIN", the the contents of the pipe stream are redirected to
* STDIN of the terminal emulator for as long as the pipe is open.
*/
guac_user_pipe_handler guac_kubernetes_pipe_handler;
#endif

View File

@ -0,0 +1,366 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "settings.h"
#include <guacamole/user.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* Client plugin arguments */
const char* GUAC_KUBERNETES_CLIENT_ARGS[] = {
"hostname",
"port",
"use-ssl",
"client-cert-file",
"client-key-file",
"ca-cert-file",
"ignore-cert",
"font-name",
"font-size",
"color-scheme",
"typescript-path",
"typescript-name",
"create-typescript-path",
"recording-path",
"recording-name",
"recording-exclude-output",
"recording-exclude-mouse",
"recording-include-keys",
"create-recording-path",
"read-only",
"backspace",
"scrollback",
NULL
};
enum KUBERNETES_ARGS_IDX {
/**
* The hostname to connect to. Required.
*/
IDX_HOSTNAME,
/**
* The port to connect to. Optional.
*/
IDX_PORT,
/**
* Whether SSL/TLS should be used. SSL is used by default.
*/
IDX_USE_SSL,
/**
* The filename of the certificate to use if performing SSL/TLS client
* authentication to authenticate with the Kubernetes server. If omitted,
* SSL client authentication will not be performed.
*/
IDX_CLIENT_CERT_FILE,
/**
* The filename of the key to use if performing SSL/TLS client
* authentication to authenticate with the Kubernetes server. If omitted,
* SSL client authentication will not be performed.
*/
IDX_CLIENT_KEY_FILE,
/**
* The filename of the certificate of the certificate authority that signed
* the certificate of the Kubernetes server.
*/
IDX_CA_CERT_FILE,
/**
* Whether the certificate used by the Kubernetes server for SSL/TLS should
* be ignored if it cannot be validated.
*/
IDX_IGNORE_CERT,
/**
* The name of the font to use within the terminal.
*/
IDX_FONT_NAME,
/**
* The size of the font to use within the terminal, in points.
*/
IDX_FONT_SIZE,
/**
* The color scheme to use, as a series of semicolon-separated color-value
* pairs: "background: <color>", "foreground: <color>", or
* "color<n>: <color>", where <n> is a number from 0 to 255, and <color> is
* "color<n>" or an X11 color code (e.g. "aqua" or "rgb:12/34/56").
* The color scheme can also be one of the special values: "black-white",
* "white-black", "gray-black", or "green-black".
*/
IDX_COLOR_SCHEME,
/**
* The full absolute path to the directory in which typescripts should be
* written.
*/
IDX_TYPESCRIPT_PATH,
/**
* The name that should be given to typescripts which are written in the
* given path. Each typescript will consist of two files: "NAME" and
* "NAME.timing".
*/
IDX_TYPESCRIPT_NAME,
/**
* Whether the specified typescript path should automatically be created
* if it does not yet exist.
*/
IDX_CREATE_TYPESCRIPT_PATH,
/**
* The full absolute path to the directory in which screen recordings
* should be written.
*/
IDX_RECORDING_PATH,
/**
* The name that should be given to screen recordings which are written in
* the given path.
*/
IDX_RECORDING_NAME,
/**
* Whether output which is broadcast to each connected client (graphics,
* streams, etc.) should NOT be included in the session recording. Output
* is included by default, as it is necessary for any recording which must
* later be viewable as video.
*/
IDX_RECORDING_EXCLUDE_OUTPUT,
/**
* Whether changes to mouse state, such as position and buttons pressed or
* released, should NOT be included in the session recording. Mouse state
* is included by default, as it is necessary for the mouse cursor to be
* rendered in any resulting video.
*/
IDX_RECORDING_EXCLUDE_MOUSE,
/**
* Whether keys pressed and released should be included in the session
* recording. Key events are NOT included by default within the recording,
* as doing so has privacy and security implications. Including key events
* may be necessary in certain auditing contexts, but should only be done
* with caution. Key events can easily contain sensitive information, such
* as passwords, credit card numbers, etc.
*/
IDX_RECORDING_INCLUDE_KEYS,
/**
* Whether the specified screen recording path should automatically be
* created if it does not yet exist.
*/
IDX_CREATE_RECORDING_PATH,
/**
* "true" if this connection should be read-only (user input should be
* dropped), "false" or blank otherwise.
*/
IDX_READ_ONLY,
/**
* ASCII code, as an integer to use for the backspace key, or 127
* if not specified.
*/
IDX_BACKSPACE,
/**
* The maximum size of the scrollback buffer in rows.
*/
IDX_SCROLLBACK,
KUBERNETES_ARGS_COUNT
};
guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
int argc, const char** argv) {
/* Validate arg count */
if (argc != KUBERNETES_ARGS_COUNT) {
guac_user_log(user, GUAC_LOG_WARNING, "Incorrect number of connection "
"parameters provided: expected %i, got %i.",
KUBERNETES_ARGS_COUNT, argc);
return NULL;
}
guac_kubernetes_settings* settings =
calloc(1, sizeof(guac_kubernetes_settings));
/* Read parameters */
settings->hostname =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_HOSTNAME, "");
/* Parse whether SSL should be used */
settings->use_ssl =
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_USE_SSL, true);
/* Read SSL/TLS connection details only if enabled */
if (settings->use_ssl) {
settings->client_cert_file =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
argv, IDX_CLIENT_CERT_FILE, NULL);
settings->client_key_file =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
argv, IDX_CLIENT_KEY_FILE, NULL);
settings->ca_cert_file =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
argv, IDX_CA_CERT_FILE, NULL);
settings->ignore_cert =
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS,
argv, IDX_IGNORE_CERT, false);
}
/* Read-only mode */
settings->read_only =
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_READ_ONLY, false);
/* Read maximum scrollback size */
settings->max_scrollback =
guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_SCROLLBACK, GUAC_KUBERNETES_DEFAULT_MAX_SCROLLBACK);
/* Read font name */
settings->font_name =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_FONT_NAME, GUAC_KUBERNETES_DEFAULT_FONT_NAME);
/* Read font size */
settings->font_size =
guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_FONT_SIZE, GUAC_KUBERNETES_DEFAULT_FONT_SIZE);
/* Copy requested color scheme */
settings->color_scheme =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_COLOR_SCHEME, "");
/* Pull width/height/resolution directly from user */
settings->width = user->info.optimal_width;
settings->height = user->info.optimal_height;
settings->resolution = user->info.optimal_resolution;
/* Read port */
settings->port =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_PORT, GUAC_KUBERNETES_DEFAULT_PORT);
/* Read typescript path */
settings->typescript_path =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_TYPESCRIPT_PATH, NULL);
/* Read typescript name */
settings->typescript_name =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_TYPESCRIPT_NAME, GUAC_KUBERNETES_DEFAULT_TYPESCRIPT_NAME);
/* Parse path creation flag */
settings->create_typescript_path =
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_CREATE_TYPESCRIPT_PATH, false);
/* Read recording path */
settings->recording_path =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_RECORDING_PATH, NULL);
/* Read recording name */
settings->recording_name =
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_RECORDING_NAME, GUAC_KUBERNETES_DEFAULT_RECORDING_NAME);
/* Parse output exclusion flag */
settings->recording_exclude_output =
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_RECORDING_EXCLUDE_OUTPUT, false);
/* Parse mouse exclusion flag */
settings->recording_exclude_mouse =
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_RECORDING_EXCLUDE_MOUSE, false);
/* Parse key event inclusion flag */
settings->recording_include_keys =
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_RECORDING_INCLUDE_KEYS, false);
/* Parse path creation flag */
settings->create_recording_path =
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_CREATE_RECORDING_PATH, false);
/* Parse backspace key code */
settings->backspace =
guac_user_parse_args_int(user, GUAC_KUBERNETES_CLIENT_ARGS, argv,
IDX_BACKSPACE, 127);
/* Parsing was successful */
return settings;
}
void guac_kubernetes_settings_free(guac_kubernetes_settings* settings) {
/* Free network connection information */
free(settings->hostname);
free(settings->port);
/* Free SSL/TLS details */
free(settings->client_cert_file);
free(settings->client_key_file);
free(settings->ca_cert_file);
/* Free display preferences */
free(settings->font_name);
free(settings->color_scheme);
/* Free typescript settings */
free(settings->typescript_name);
free(settings->typescript_path);
/* Free screen recording settings */
free(settings->recording_name);
free(settings->recording_path);
/* Free overall structure */
free(settings);
}

View File

@ -0,0 +1,256 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUAC_KUBERNETES_SETTINGS_H
#define GUAC_KUBERNETES_SETTINGS_H
#include "config.h"
#include <guacamole/user.h>
#include <sys/types.h>
#include <stdbool.h>
/**
* The name of the font to use for the terminal if no name is specified.
*/
#define GUAC_KUBERNETES_DEFAULT_FONT_NAME "monospace"
/**
* The size of the font to use for the terminal if no font size is specified,
* in points.
*/
#define GUAC_KUBERNETES_DEFAULT_FONT_SIZE 12
/**
* The port to connect to when initiating any Kubernetes connection, if no
* other port is specified.
*/
#define GUAC_KUBERNETES_DEFAULT_PORT "8443"
/**
* The filename to use for the typescript, if not specified.
*/
#define GUAC_KUBERNETES_DEFAULT_TYPESCRIPT_NAME "typescript"
/**
* The filename to use for the screen recording, if not specified.
*/
#define GUAC_KUBERNETES_DEFAULT_RECORDING_NAME "recording"
/**
* The default maximum scrollback size in rows.
*/
#define GUAC_KUBERNETES_DEFAULT_MAX_SCROLLBACK 1000
/**
* Settings for the Kubernetes connection. The values for this structure are
* parsed from the arguments given during the Guacamole protocol handshake
* using the guac_kubernetes_parse_args() function.
*/
typedef struct guac_kubernetes_settings {
/**
* The hostname of the Kubernetes server to connect to.
*/
char* hostname;
/**
* The port of the Kubernetes server to connect to.
*/
char* port;
/**
* Whether SSL/TLS should be used.
*/
bool use_ssl;
/**
* The filename of the certificate to use if performing SSL/TLS client
* authentication to authenticate with the Kubernetes server. If omitted,
* SSL client authentication will not be performed.
*/
char* client_cert_file;
/**
* The filename of the key to use if performing SSL/TLS client
* authentication to authenticate with the Kubernetes server. If omitted,
* SSL client authentication will not be performed.
*/
char* client_key_file;
/**
* The filename of the certificate of the certificate authority that signed
* the certificate of the Kubernetes server.
*/
char* ca_cert_file;
/**
* Whether the certificate used by the Kubernetes server for SSL/TLS should
* be ignored if it cannot be validated.
*/
bool ignore_cert;
/**
* Whether this connection is read-only, and user input should be dropped.
*/
bool read_only;
/**
* The maximum size of the scrollback buffer in rows.
*/
int max_scrollback;
/**
* The name of the font to use for display rendering.
*/
char* font_name;
/**
* The size of the font to use, in points.
*/
int font_size;
/**
* The name of the color scheme to use.
*/
char* color_scheme;
/**
* The desired width of the terminal display, in pixels.
*/
int width;
/**
* The desired height of the terminal display, in pixels.
*/
int height;
/**
* The desired screen resolution, in DPI.
*/
int resolution;
/**
* The path in which the typescript should be saved, if enabled. If no
* typescript should be saved, this will be NULL.
*/
char* typescript_path;
/**
* The filename to use for the typescript, if enabled.
*/
char* typescript_name;
/**
* Whether the typescript path should be automatically created if it does
* not already exist.
*/
bool create_typescript_path;
/**
* The path in which the screen recording should be saved, if enabled. If
* no screen recording should be saved, this will be NULL.
*/
char* recording_path;
/**
* The filename to use for the screen recording, if enabled.
*/
char* recording_name;
/**
* Whether the screen recording path should be automatically created if it
* does not already exist.
*/
bool create_recording_path;
/**
* Whether output which is broadcast to each connected client (graphics,
* streams, etc.) should NOT be included in the session recording. Output
* is included by default, as it is necessary for any recording which must
* later be viewable as video.
*/
bool recording_exclude_output;
/**
* Whether changes to mouse state, such as position and buttons pressed or
* released, should NOT be included in the session recording. Mouse state
* is included by default, as it is necessary for the mouse cursor to be
* rendered in any resulting video.
*/
bool recording_exclude_mouse;
/**
* Whether keys pressed and released should be included in the session
* recording. Key events are NOT included by default within the recording,
* as doing so has privacy and security implications. Including key events
* may be necessary in certain auditing contexts, but should only be done
* with caution. Key events can easily contain sensitive information, such
* as passwords, credit card numbers, etc.
*/
bool recording_include_keys;
/**
* The ASCII code, as an integer, that the Kubernetes client will use when
* the backspace key is pressed. By default, this is 127, ASCII delete, if
* not specified in the client settings.
*/
int backspace;
} guac_kubernetes_settings;
/**
* Parses all given args, storing them in a newly-allocated settings object. If
* the args fail to parse, NULL is returned.
*
* @param user
* The user who submitted the given arguments while joining the
* connection.
*
* @param argc
* The number of arguments within the argv array.
*
* @param argv
* The values of all arguments provided by the user.
*
* @return
* A newly-allocated settings object which must be freed with
* guac_kubernetes_settings_free() when no longer needed. If the arguments
* fail to parse, NULL is returned.
*/
guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
int argc, const char** argv);
/**
* Frees the given guac_kubernetes_settings object, having been previously
* allocated via guac_kubernetes_parse_args().
*
* @param settings
* The settings object to free.
*/
void guac_kubernetes_settings_free(guac_kubernetes_settings* settings);
/**
* NULL-terminated array of accepted client args.
*/
extern const char* GUAC_KUBERNETES_CLIENT_ARGS[];
#endif

View File

@ -0,0 +1,116 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "clipboard.h"
#include "input.h"
#include "kubernetes.h"
#include "pipe.h"
#include "settings.h"
#include "terminal/terminal.h"
#include "user.h"
#include <guacamole/client.h>
#include <guacamole/socket.h>
#include <guacamole/user.h>
#include <pthread.h>
#include <string.h>
int guac_kubernetes_user_join_handler(guac_user* user, int argc, char** argv) {
guac_client* client = user->client;
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) client->data;
/* Parse provided arguments */
guac_kubernetes_settings* settings = guac_kubernetes_parse_args(user,
argc, (const char**) argv);
/* Fail if settings cannot be parsed */
if (settings == NULL) {
guac_user_log(user, GUAC_LOG_INFO,
"Badly formatted client arguments.");
return 1;
}
/* Store settings at user level */
user->data = settings;
/* Connect to Kubernetes if owner */
if (user->owner) {
/* Store owner's settings at client level */
kubernetes_client->settings = settings;
/* Start client thread */
if (pthread_create(&(kubernetes_client->client_thread), NULL,
guac_kubernetes_client_thread, (void*) client)) {
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
"Unable to start Kubernetes client thread");
return 1;
}
}
/* If not owner, synchronize with current display */
else {
guac_terminal_dup(kubernetes_client->term, user, user->socket);
guac_socket_flush(user->socket);
}
/* Only handle events if not read-only */
if (!settings->read_only) {
/* General mouse/keyboard/clipboard events */
user->key_handler = guac_kubernetes_user_key_handler;
user->mouse_handler = guac_kubernetes_user_mouse_handler;
user->clipboard_handler = guac_kubernetes_clipboard_handler;
/* STDIN redirection */
user->pipe_handler = guac_kubernetes_pipe_handler;
/* Display size change events */
user->size_handler = guac_kubernetes_user_size_handler;
}
return 0;
}
int guac_kubernetes_user_leave_handler(guac_user* user) {
guac_kubernetes_client* kubernetes_client =
(guac_kubernetes_client*) user->client->data;
/* Update shared cursor state */
guac_common_cursor_remove_user(kubernetes_client->term->cursor, user);
/* Free settings if not owner (owner settings will be freed with client) */
if (!user->owner) {
guac_kubernetes_settings* settings =
(guac_kubernetes_settings*) user->data;
guac_kubernetes_settings_free(settings);
}
return 0;
}

View File

@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUAC_KUBERNETES_USER_H
#define GUAC_KUBERNETES_USER_H
#include "config.h"
#include <guacamole/user.h>
/**
* Handler for joining users.
*/
guac_user_join_handler guac_kubernetes_user_join_handler;
/**
* Handler for leaving users.
*/
guac_user_leave_handler guac_kubernetes_user_leave_handler;
#endif