diff --git a/README.md b/README.md index bdcd1fc4..c37783ac 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,7 @@ OPTIONS: -g, --gid Group id to run with -s, --signal Signal to send to the command when exit it (default: 1, SIGHUP) -a, --url-arg Allow client to send command line arguments in URL (eg: http://localhost:7681?arg=foo&arg=bar) + -f, --arg-file File prefix for a unique generated temp file that URL arguments are written to (ex. /tmp/prefix); the generated file's full path is then passed in as a command line argument (ex. /tmp/prefix{unique string}) -R, --readonly Do not allow clients to write to the TTY -t, --client-option Send option to client (format: key=value), repeat to add more options -T, --terminal-type Terminal type to report, default: xterm-256color diff --git a/man/ttyd.1 b/man/ttyd.1 index c4e76ee4..0f124515 100644 --- a/man/ttyd.1 +++ b/man/ttyd.1 @@ -71,6 +71,9 @@ Cross platform: macOS, Linux, FreeBSD/OpenBSD, OpenWrt/LEDE, Windows Allow client to send command line arguments in URL (eg: \[la]http://localhost:7681?arg=foo&arg=bar\[ra]) +.PP +\-f, \-\-arg\-file + File prefix for a unique generated temp file that URL arguments are written to (ex. /tmp/prefix); the generated file's full path is then passed in as a command line argument (ex. /tmp/prefix{unique string}). The command is responsible for deleting the file. .PP \-R, \-\-readonly Do not allow clients to write to the TTY diff --git a/man/ttyd.man.md b/man/ttyd.man.md index 99c39941..b09a2a11 100644 --- a/man/ttyd.man.md +++ b/man/ttyd.man.md @@ -46,6 +46,9 @@ ttyd 1 "September 2016" ttyd "User Manual" -a, --url-arg Allow client to send command line arguments in URL (eg: http://localhost:7681?arg=foo&arg=bar) + -f, --arg-file + File prefix for a unique generated temp file that URL arguments are written to (ex. /tmp/prefix); the generated file's full path is then passed in as a command line argument (ex. /tmp/prefix{unique string}). The command is responsible for deleting the file. + -R, --readonly Do not allow clients to write to the TTY diff --git a/src/protocol.c b/src/protocol.c index ca1e0869..1a5d7bee 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -101,8 +101,37 @@ static char **build_args(struct pss_tty *pss) { argv[n++] = server->argv[i]; } - for (i = 0; i < pss->argc; i++) { - argv[n++] = pss->args[i]; + if (server->url_arg) { + for (i = 0; i < pss->argc; i++) { + argv[n++] = pss->args[i]; + } + } else if (server->arg_file != NULL) { + int fd = -1; + int file_path_len = strlen(server->arg_file) + 6 /*XXXXXX*/ + 1 /*null character*/; + char *filePath = xmalloc(file_path_len); + snprintf(filePath, file_path_len, "%sXXXXXX", server->arg_file); + + if ((fd = mkstemp(filePath)) == -1) { + lwsl_err("Creation of temp file failed with error: %d (%s)\n", errno, strerror(errno)); + free(filePath); + return false; + } + + for (i = 0; i < pss->argc; i++) { + if (dprintf(fd, "%s\n", pss->args[i]) < 0) { + lwsl_err("Write to temp file failed with error: %d (%s)\n", errno, strerror(errno)); + close(fd); + free(filePath); + return false; + } + } + + if (close(fd) != 0) { + lwsl_err("Close temp file failed with error: %d (%s)\n", errno, strerror(errno)); + free(filePath); + return false; + } + argv[n++] = filePath; } argv[n] = NULL; @@ -219,7 +248,7 @@ int callback_tty(struct lws *wsi, enum lws_callback_reasons reason, void *user, pss->wsi = wsi; pss->lws_close_status = LWS_CLOSE_STATUS_NOSTATUS; - if (server->url_arg) { + if (server->url_arg || server->arg_file != NULL) { while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_URI_ARGS, n++) > 0) { if (strncmp(buf, "arg=", 4) == 0) { pss->args = xrealloc(pss->args, (pss->argc + 1) * sizeof(char *)); diff --git a/src/server.c b/src/server.c index f9113afd..1f1d01b7 100644 --- a/src/server.c +++ b/src/server.c @@ -70,6 +70,7 @@ static const struct option options[] = {{"port", required_argument, NULL, 'p'}, {"ssl-key", required_argument, NULL, 'K'}, {"ssl-ca", required_argument, NULL, 'A'}, {"url-arg", no_argument, NULL, 'a'}, + {"arg-file", required_argument, NULL, 'f'}, {"readonly", no_argument, NULL, 'R'}, {"terminal-type", required_argument, NULL, 'T'}, {"client-option", required_argument, NULL, 't'}, @@ -81,7 +82,7 @@ static const struct option options[] = {{"port", required_argument, NULL, 'p'}, {"version", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, 0, 0}}; -static const char *opt_string = "p:i:c:H:u:g:s:w:I:b:P:6aSC:K:A:Rt:T:Om:oBd:vh"; +static const char *opt_string = "p:i:c:H:u:g:s:w:I:b:P:6af:SC:K:A:Rt:T:Om:oBd:vh"; static void print_help() { // clang-format off @@ -100,6 +101,7 @@ static void print_help() { " -s, --signal Signal to send to the command when exit it (default: 1, SIGHUP)\n" " -w, --cwd Working directory to be set for the child program\n" " -a, --url-arg Allow client to send command line arguments in URL (eg: http://localhost:7681?arg=foo&arg=bar)\n" + " -f, --arg-file File prefix for a unique generated temp file that URL arguments are written to (ex. /tmp/prefix); the generated file's full path is then passed in as a command line argument (ex. /tmp/prefix{unique string}). The command is responsible for deleting the file.\n" " -R, --readonly Do not allow clients to write to the TTY\n" " -t, --client-option Send option to client (format: key=value), repeat to add more options\n" " -T, --terminal-type Terminal type to report, default: xterm-256color\n" @@ -146,6 +148,7 @@ static void print_config() { if (server->auth_header != NULL) lwsl_notice(" auth header: %s\n", server->auth_header); if (server->check_origin) lwsl_notice(" check origin: true\n"); if (server->url_arg) lwsl_notice(" allow url arg: true\n"); + if (server->arg_file != NULL) lwsl_notice(" temp file name prefix: %s\n", server->arg_file); if (server->readonly) lwsl_notice(" readonly: true\n"); if (server->max_clients > 0) lwsl_notice(" max clients: %d\n", server->max_clients); if (server->once) lwsl_notice(" once: true\n"); @@ -197,6 +200,7 @@ static struct server *server_new(int argc, char **argv, int start) { static void server_free(struct server *ts) { if (ts == NULL) return; + if (ts->arg_file != NULL) free(ts->arg_file); if (ts->credential != NULL) free(ts->credential); if (ts->auth_header != NULL) free(ts->auth_header); if (ts->index != NULL) free(ts->index); @@ -346,6 +350,11 @@ int main(int argc, char **argv) { break; case 'a': server->url_arg = true; + server->arg_file = NULL; + break; + case 'f': + server->arg_file = strdup(optarg); + server->url_arg = false; break; case 'R': server->readonly = true; diff --git a/src/server.h b/src/server.h index b122d1c1..749bf9cd 100644 --- a/src/server.h +++ b/src/server.h @@ -69,6 +69,7 @@ struct server { int sig_code; // close signal char sig_name[20]; // human readable signal string bool url_arg; // allow client to send cli arguments in URL + char *arg_file; // file prefix for a generated temp file that URL arguments are written to bool readonly; // whether not allow clients to write to the TTY bool check_origin; // whether allow websocket connection from different origin int max_clients; // maximum clients to support