From 9af62fa24d3216841e0dd8c43a517a195d61ef13 Mon Sep 17 00:00:00 2001 From: Alex Karle Date: Sat, 24 Apr 2021 00:28:31 -0400 Subject: [PATCH] kiosk: Add MVP ssh kiosk program to browse blog via ssh+mandoc I'm really excited (if a bit nervous about the security implications) about this kiosk program. I've always thought it'd be cool to browse my site via mandoc(1), so I wrote a simple shell-like program called 'kiosk' that lists the man pages in the site and asks which you'd like to read (with some other options to quit, list, or see help). This isn't 100% ready to go live (as a public SSH option), but it's at a state where it's worth checking in! --- .gitignore | 3 +++ Makefile | 9 ++++++++- src/kiosk.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/kiosk.c diff --git a/.gitignore b/.gitignore index d84848a..ef6650f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ atom.xml # jam-tuesday hits generated by jam-tuesday/stats.sh jam-tuesday/greatest-hits + +# binaries +bin/ diff --git a/Makefile b/Makefile index fc7ac3f..c70e4da 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,11 @@ SETS != find jam-tuesday -name '[01][0-9]-*' # of the abbreviated version (@ suppresses the command in make) HIDE = @ +CC = cc +CFLAGS = -g -O2 -Wall -Wpedantic -Wextra + .PHONY: build -build: $(HTML) atom.xml jam-tuesday/greatest-hits +build: $(HTML) atom.xml jam-tuesday/greatest-hits bin/kiosk .PHONY: clean clean: @@ -25,6 +28,10 @@ atom.xml: blog.7 genatom.sh jam-tuesday/greatest-hits: $(SETS) jam-tuesday/stats.sh (date; echo; ./jam-tuesday/stats.sh) > $@ +bin/kiosk: src/kiosk.c + mkdir -p bin + $(CC) $(CFLAGS) -DMANDIR="\"`pwd`\"" $< -o $@ + $(HTML): Makefile .SUFFIXES: .7 .html diff --git a/src/kiosk.c b/src/kiosk.c new file mode 100644 index 0000000..767e431 --- /dev/null +++ b/src/kiosk.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include + +int list(void) { + DIR *dirp = opendir(MANDIR); + struct dirent *dp; + int n = 0; + while ((dp = readdir(dirp)) != NULL) { + size_t len = strlen(dp->d_name); + if (len < 3) + continue; + if (strcmp(dp->d_name + (len - 2), ".7") == 0) { + dp->d_name[len - 2] = '\0'; /* truncate extension */ + printf("%2d: %s(7)\n", ++n, dp->d_name); + } + } + closedir(dirp); + printf(" l: list\n"); + printf(" h: help\n"); + printf(" q: quit\n"); + return n; +} + +void help(void) { + printf( + "Welcome to alexkarle.com's SSH Kiosk!\n" + "\n" + "Here you'll find all the mdoc(7) contents of my blog, rendered\n" + "in their original form via mandoc(1).\n" + "\n" + "Currently, due to security concerns, only the blog posts are\n" + "browsable (and no shell access is given).\n" + "\n" + "If you think this is cool, I'd love to hear from you!\n" + "Drop me a line at alex@alexkarle.com!\n" + ); + +} + +/* TODO: have list() read into memory so we don't readdir each time! */ +void mandoc(int choice) { + DIR *dirp = opendir(MANDIR); + struct dirent *dp; + int i = 0; + while ((dp = readdir(dirp)) != NULL) { + size_t len = strlen(dp->d_name); + if (len < 3) + continue; + if (strcmp(dp->d_name + (len - 2), ".7") == 0) { + if (++i == choice) { + char *cmd_base = "mandoc -l"; + char cmd[sizeof(cmd_base) + PATH_MAX + 2]; + sprintf(cmd, "%s %s/%s", cmd_base, MANDIR, dp->d_name); + system(cmd); + break; + } + } + } + closedir(dirp); +} + +void prompt(int n) { + printf("choice> "); + fflush(stdout); + + /* NOTE: Read from /dev/tty instead of stdin to prevent + * simple DDOS via < /dev/random */ + + FILE *tty = fopen("/dev/tty", "r"); + char *line = NULL; + size_t line_len; + ssize_t nread = getline(&line, &line_len, tty); + if (nread == -1 || strcmp(line, "q\n") == 0) { + printf("Goodbye!\n"); + exit(0); + } + fclose(tty); + + int choice; + if (strcmp(line, "l\n") == 0) { + list(); + } else if (strcmp(line, "h\n") == 0) { + help(); + } else if (nread == 1) { + /* must be blank line... no-op */ + } else if (sscanf(line, "%d\n", &choice) == 0) { + printf("Bad input: %s", line); + } else if (choice > n || choice <= 0) { + printf("Choice %d out of bounds\n", choice); + } else { + mandoc(choice); + } + + free(line); +} + +int main(void) { + int n = list(); + setenv("MANPAGER", "less", 0); + setenv("LESSSECURE", "1", 1); + for(;;) + prompt(n); + return 0; +} -- libgit2 1.1.1