#define BUF_SIZE 1024
-char *
-base64_encode(const unsigned char *buffer, size_t length) {
- BIO *bio, *b64;
- BUF_MEM *bptr;
-
- b64 = BIO_new(BIO_f_base64());
- bio = BIO_new(BIO_s_mem());
- b64 = BIO_push(b64, bio);
-
- BIO_write(b64, buffer, (int) length);
- BIO_flush(b64);
- BIO_get_mem_ptr(b64, &bptr);
-
- char *data = (char *)malloc(bptr->length);
- memcpy(data, bptr->data, bptr->length-1);
- data[bptr->length-1] = 0;
-
- BIO_free_all(b64);
-
- return data;
-}
-
int
send_initial_message(struct lws *wsi) {
unsigned char message[LWS_PRE + 256];
}
rows = json_object_get_int(o);
- struct winsize *size = malloc(sizeof(struct winsize));
+ struct winsize *size = t_malloc(sizeof(struct winsize));
memset(size, 0, sizeof(struct winsize));
size->ws_col = (unsigned short) columns;
size->ws_row = (unsigned short) rows;
if (FD_ISSET (pty, &des_set)) {
memset(buf, 0, BUF_SIZE);
bytes = (int) read(pty, buf, BUF_SIZE);
- struct pty_data *frame = (struct pty_data *) malloc(sizeof(struct pty_data));
+ struct pty_data *frame = (struct pty_data *) t_malloc(sizeof(struct pty_data));
frame->len = bytes;
if (bytes > 0) {
- frame->data = malloc((size_t) bytes);
+ frame->data = t_malloc((size_t) bytes);
memcpy(frame->data, buf, bytes);
}
pthread_mutex_lock(&client->lock);
// read error or client exited, close connection
if (frame->len <= 0) {
STAILQ_REMOVE_HEAD(&client->queue, list);
- free(frame);
+ t_free(frame);
return -1;
}
unsigned char *p = &message[LWS_PRE];
size_t n = sprintf((char *) p, "%c%s", OUTPUT, b64_text);
- free(b64_text);
+ t_free(b64_text);
if (lws_write(wsi, p, n, LWS_WRITE_TEXT) < n) {
lwsl_err("lws_write\n");
}
STAILQ_REMOVE_HEAD(&client->queue, list);
- free(frame->data);
- free(frame);
+ t_free(frame->data);
+ t_free(frame);
if(lws_partial_buffered(wsi)){
lws_callback_on_writable(wsi);
if (ioctl(client->pty, TIOCSWINSZ, size) == -1) {
lwsl_err("ioctl TIOCSWINSZ: %d (%s)\n", errno, strerror(errno));
}
- free(size);
+ t_free(size);
}
break;
default:
#include "server.h"
-#ifdef __linux__
-/*
- * sys_signame -- an ordered list of signals.
- * lifted from /usr/include/linux/signal.h
- * this particular order is only correct for linux.
- * this is _not_ portable.
- */
-const char *sys_signame[NSIG] = {
- "zero", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "UNUSED",
- "FPE", "KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM",
- "STKFLT","CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU", "IO",
- "XCPU", "XFSZ", "VTALRM","PROF", "WINCH", NULL
-};
-#endif
-
volatile bool force_exit = false;
struct lws_context *context;
struct tty_server *server;
// websocket protocols
static const struct lws_protocols protocols[] = {
- {"http-only", callback_http, 0, 0},
- {"tty", callback_tty, sizeof(struct tty_client), 128},
- {NULL, NULL, 0, 0}
+ {"http-only", callback_http, 0, 0},
+ {"tty", callback_tty, sizeof(struct tty_client), 128},
+ {NULL, NULL, 0, 0}
};
// websocket extensions
static const struct lws_extension extensions[] = {
{"permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate"},
- {"deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame"},
+ {"deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame"},
{NULL, NULL, NULL}
};
// command line options
static const struct option options[] = {
- {"port", required_argument, NULL, 'p'},
- {"interface", required_argument, NULL, 'i'},
- {"credential", required_argument, NULL, 'c'},
- {"uid", required_argument, NULL, 'u'},
- {"gid", required_argument, NULL, 'g'},
- {"signal", required_argument, NULL, 's'},
- {"reconnect", required_argument, NULL, 'r'},
-#ifdef LWS_OPENSSL_SUPPORT
- {"ssl", no_argument, NULL, 'S'},
- {"ssl-cert", required_argument, NULL, 'C'},
- {"ssl-key", required_argument, NULL, 'K'},
- {"ssl-ca", required_argument, NULL, 'A'},
-#endif
- {"debug", required_argument, NULL, 'd'},
- {"help", no_argument, NULL, 'h'},
- {NULL, 0, 0, 0}
+ {"port", required_argument, NULL, 'p'},
+ {"interface", required_argument, NULL, 'i'},
+ {"credential", required_argument, NULL, 'c'},
+ {"uid", required_argument, NULL, 'u'},
+ {"gid", required_argument, NULL, 'g'},
+ {"signal", required_argument, NULL, 's'},
+ {"reconnect", required_argument, NULL, 'r'},
+ {"ssl", no_argument, NULL, 'S'},
+ {"ssl-cert", required_argument, NULL, 'C'},
+ {"ssl-key", required_argument, NULL, 'K'},
+ {"ssl-ca", required_argument, NULL, 'A'},
+ {"debug", required_argument, NULL, 'd'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, 0, 0}
};
static const char *opt_string = "p:i:c:u:g:s:r:aSC:K:A:d:vh";
void print_help() {
fprintf(stderr, "ttyd is a tool for sharing terminal over the web\n\n"
- "USAGE: ttyd [options] <command> [<arguments...>]\n\n"
- "OPTIONS:\n"
- "\t--port, -p Port to listen (default: 7681)\n"
- "\t--interface, -i Network interface to bind\n"
- "\t--credential, -c Credential for Basic Authentication (format: username:password)\n"
- "\t--uid, -u User id to run with\n"
- "\t--gid, -g Group id to run with\n"
- "\t--signal, -s Signal to send to the command when exit it (default: SIGHUP)\n"
- "\t--reconnect, -r Time to reconnect for the client in seconds (default: 10)\n"
-#ifdef LWS_OPENSSL_SUPPORT
- "\t--ssl, -S Enable ssl\n"
- "\t--ssl-cert, -C Ssl certificate file path\n"
- "\t--ssl-key, -K Ssl key file path\n"
- "\t--ssl-ca, -A Ssl ca file path\n"
-#endif
- "\t--debug, -d Set log level (0-9, default: 7)\n"
- "\t--help, -h Print this text and exit\n"
+ "USAGE: ttyd [options] <command> [<arguments...>]\n\n"
+ "OPTIONS:\n"
+ "\t--port, -p Port to listen (default: 7681)\n"
+ "\t--interface, -i Network interface to bind\n"
+ "\t--credential, -c Credential for Basic Authentication (format: username:password)\n"
+ "\t--uid, -u User id to run with\n"
+ "\t--gid, -g Group id to run with\n"
+ "\t--signal, -s Signal to send to the command when exit it (default: SIGHUP)\n"
+ "\t--reconnect, -r Time to reconnect for the client in seconds (default: 10)\n"
+ "\t--ssl, -S Enable ssl\n"
+ "\t--ssl-cert, -C Ssl certificate file path\n"
+ "\t--ssl-key, -K Ssl key file path\n"
+ "\t--ssl-ca, -A Ssl ca file path\n"
+ "\t--debug, -d Set log level (0-9, default: 7)\n"
+ "\t--help, -h Print this text and exit\n"
);
}
-struct tty_server*
+struct tty_server *
tty_server_new(int argc, char **argv) {
struct tty_server *ts;
size_t cmd_len = 0;
- ts = malloc(sizeof(struct tty_server));
+ ts = t_malloc(sizeof(struct tty_server));
LIST_INIT(&ts->clients);
ts->client_count = 0;
ts->credential = NULL;
ts->reconnect = 10;
ts->sig_code = SIGHUP;
ts->sig_name = strdup("SIGHUP");
- ts->argv = malloc(sizeof(char *) * (argc + 1));
+ ts->argv = t_malloc(sizeof(char *) * (argc + 1));
for (int i = 0; i < argc; i++) {
ts->argv[i] = strdup(argv[i]);
cmd_len += strlen(ts->argv[i]);
}
ts->argv[argc] = NULL;
- ts->command = malloc(cmd_len);
+ ts->command = t_malloc(cmd_len);
char *ptr = ts->command;
for (int i = 0; i < argc; i++) {
ptr = stpcpy(ptr, ts->argv[i]);
- if (i != argc -1) {
+ if (i != argc - 1) {
sprintf(ptr++, "%c", ' ');
}
}
return ts;
}
-char *
-uppercase(char *str) {
- int i = 0;
- do {
- str[i] = (char) toupper(str[i]);
- } while (str[i++] != '\0');
- return str;
-}
-
-// Get human readable signal string
-int
-get_sig_name(int sig, char *buf) {
- int n = sprintf(buf, "SIG%s", sig < NSIG ? sys_signame[sig] : "unknown");
- uppercase(buf);
- return n;
-}
-
-// Get signal code from string like SIGHUP
-int
-get_sig(const char *sig_name) {
- if (strcasestr(sig_name, "sig") != sig_name || strlen(sig_name) <= 3) {
- return -1;
- }
- for (int sig = 1; sig < NSIG; sig++) {
- const char *name = sys_signame[sig];
- if (strcasecmp(name, sig_name + 3) == 0)
- return sig;
- }
- return -1;
-}
-
void
sig_handler(int sig) {
char sig_name[20];
calc_command_start(int argc, char **argv) {
// make a copy of argc and argv
int argc_copy = argc;
- char **argv_copy = malloc(sizeof(char *) * argc);
+ char **argv_copy = t_malloc(sizeof(char *) * argc);
for (int i = 0; i < argc; i++) {
argv_copy[i] = strdup(argv[i]);
}
// do not print error message for invalid option
opterr = 0;
- while(getopt_long(argc_copy, argv_copy, opt_string, options, NULL) != -1)
- ;;
- int start= -1;
+ while (getopt_long(argc_copy, argv_copy, opt_string, options, NULL) != -1);
+
+ int start = -1;
if (optind < argc) {
char *command = argv_copy[optind];
for (int i = 0; i < argc; i++) {
// free argv copy
for (int i = 0; i < argc; i++) {
- free(argv_copy[i]);
+ t_free(argv_copy[i]);
}
- free(argv_copy);
+ t_free(argv_copy);
// reset for next use
opterr = 1;
int debug_level = 7;
char iface[128] = "";
-#ifdef LWS_OPENSSL_SUPPORT
bool ssl = false;
char cert_path[1024] = "";
char key_path[1024] = "";
char ca_path[1024] = "";
-#endif
// parse command line options
int c;
break;
case 'i':
strncpy(iface, optarg, sizeof(iface));
- iface[sizeof(iface)-1] = '\0';
+ iface[sizeof(iface) - 1] = '\0';
break;
case 'c':
if (strchr(optarg, ':') == NULL) {
case 'g':
info.gid = atoi(optarg);
break;
- case 's':
- {
- int sig = get_sig(optarg);
- if (sig > 0) {
- server->sig_code = get_sig(optarg);
- server->sig_name = uppercase(strdup(optarg));
- } else {
- fprintf(stderr, "ttyd: invalid signal: %s\n", optarg);
- return -1;
- }
+ case 's': {
+ int sig = get_sig(optarg);
+ if (sig > 0) {
+ server->sig_code = get_sig(optarg);
+ server->sig_name = uppercase(strdup(optarg));
+ } else {
+ fprintf(stderr, "ttyd: invalid signal: %s\n", optarg);
+ return -1;
}
+ }
break;
case 'r':
server->reconnect = atoi(optarg);
break;
-#ifdef LWS_OPENSSL_SUPPORT
case 'S':
ssl = true;
break;
strncpy(ca_path, optarg, sizeof(ca_path) - 1);
ca_path[sizeof(ca_path) - 1] = '\0';
break;
-#endif
case '?':
break;
default:
if (strlen(iface) > 0)
info.iface = iface;
-#ifdef LWS_OPENSSL_SUPPORT
if (ssl) {
info.ssl_cert_filepath = cert_path;
info.ssl_private_key_filepath = key_path;
info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS;
#endif
}
-#endif
signal(SIGINT, sig_handler);
// cleanup
if (server->credential != NULL)
- free(server->credential);
- free(server->command);
+ t_free(server->credential);
+ t_free(server->command);
int i = 0;
do {
- free(server->argv[i++]);
+ t_free(server->argv[i++]);
} while (server->argv[i] != NULL);
- free(server->argv);
- free(server->sig_name);
- free(server);
+ t_free(server->argv);
+ t_free(server->sig_name);
+ t_free(server);
return 0;
}
--- /dev/null
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <signal.h>
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+#include <openssl/buffer.h>
+
+// http://web.mit.edu/~svalente/src/kill/kill.c
+#ifdef __linux__
+/*
+ * sys_signame -- an ordered list of signals.
+ * lifted from /usr/include/linux/signal.h
+ * this particular order is only correct for linux.
+ * this is _not_ portable.
+ */
+const char *sys_signame[NSIG] = {
+ "zero", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "UNUSED",
+ "FPE", "KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM",
+ "STKFLT","CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU", "IO",
+ "XCPU", "XFSZ", "VTALRM","PROF", "WINCH", NULL
+};
+#endif
+
+void *
+t_malloc(size_t size) {
+ if (size == 0)
+ return NULL;
+ void *p = malloc(size);
+ if (!p)
+ abort();
+ return p;
+}
+
+void t_free(void *p) {
+ if (p)
+ free(p);
+}
+
+void *
+t_realloc(void *p, size_t size) {
+ if ((size == 0) && (p == NULL))
+ return NULL;
+ p = realloc(p, size);
+ if (!p)
+ abort();
+ return p;
+}
+
+char *
+uppercase(char *str) {
+ int i = 0;
+ do {
+ str[i] = (char) toupper(str[i]);
+ } while (str[i++] != '\0');
+ return str;
+}
+
+int
+get_sig_name(int sig, char *buf) {
+ int n = sprintf(buf, "SIG%s", sig < NSIG ? sys_signame[sig] : "unknown");
+ uppercase(buf);
+ return n;
+}
+
+int
+get_sig(const char *sig_name) {
+ if (strcasestr(sig_name, "sig") != sig_name || strlen(sig_name) <= 3) {
+ return -1;
+ }
+ for (int sig = 1; sig < NSIG; sig++) {
+ const char *name = sys_signame[sig];
+ if (strcasecmp(name, sig_name + 3) == 0)
+ return sig;
+ }
+ return -1;
+}
+
+char *
+base64_encode(const unsigned char *buffer, size_t length) {
+ BIO *bio, *b64;
+ BUF_MEM *bptr;
+
+ b64 = BIO_new(BIO_f_base64());
+ bio = BIO_new(BIO_s_mem());
+ b64 = BIO_push(b64, bio);
+
+ BIO_write(b64, buffer, (int) length);
+ BIO_flush(b64);
+ BIO_get_mem_ptr(b64, &bptr);
+
+ char *data = (char *) t_malloc(bptr->length);
+ memcpy(data, bptr->data, bptr->length - 1);
+ data[bptr->length - 1] = 0;
+
+ BIO_free_all(b64);
+
+ return data;
+}
\ No newline at end of file