kiosk.c (2673B) [raw]
1 #include <dirent.h> 2 #include <err.h> 3 #include <limits.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <fcntl.h> 9 10 int list(void) { 11 DIR *dirp = opendir(MANDIR); 12 struct dirent *dp; 13 int n = 0; 14 while ((dp = readdir(dirp)) != NULL) { 15 /* ignore hidden files (and, conveniently, . and ..) */ 16 if (dp->d_name[0] != '.') { 17 printf("%2d: %s(7)\n", ++n, dp->d_name); 18 } 19 } 20 closedir(dirp); 21 printf(" l: list\n"); 22 printf(" h: help\n"); 23 printf(" q: quit\n"); 24 return n; 25 } 26 27 void help(void) { 28 printf( 29 "Welcome to alexkarle.com's SSH Kiosk!\n" 30 "\n" 31 "Here you'll find all the mdoc(7) contents of my blog, rendered\n" 32 "in their original form via mandoc(1).\n" 33 "\n" 34 "Currently, due to security concerns, only the blog posts are\n" 35 "browsable (and no shell access is given).\n" 36 "\n" 37 "If you think this is cool, I'd love to hear from you!\n" 38 "Drop me a line at alex@alexkarle.com!\n" 39 ); 40 41 } 42 43 /* TODO: have list() read into memory so we don't readdir each time! */ 44 void mandoc(int choice) { 45 DIR *dirp = opendir(MANDIR); 46 struct dirent *dp; 47 int i = 0; 48 while ((dp = readdir(dirp)) != NULL) { 49 if (dp->d_name[0] != '.' && ++i == choice) { 50 char path[PATH_MAX]; 51 sprintf(path, "%s/%s", MANDIR, dp->d_name); 52 FILE *fd = fopen(path, "r"); 53 if (fd == NULL) 54 err(1, "open"); 55 char c; 56 while ((c = getc(fd)) != EOF) { 57 putc(c, stdout); 58 } 59 fclose(fd); 60 break; 61 } 62 } 63 closedir(dirp); 64 } 65 66 void prompt(int n) { 67 printf("kiosk> "); 68 fflush(stdout); 69 70 /* NOTE: Read from /dev/tty instead of stdin to prevent 71 * simple DDOS via < /dev/random */ 72 73 FILE *tty = fopen("/dev/tty", "r"); 74 if (tty == NULL) 75 errx(1, "unable to open tty"); 76 char *line = NULL; 77 size_t line_len; 78 ssize_t nread = getline(&line, &line_len, tty); 79 if (nread == -1 || strcmp(line, "q\n") == 0) { 80 printf("Goodbye!\n"); 81 exit(0); 82 } 83 fclose(tty); 84 85 int choice; 86 if (strcmp(line, "l\n") == 0) { 87 list(); 88 } else if (strcmp(line, "h\n") == 0) { 89 help(); 90 } else if (nread == 1) { 91 /* must be blank line... no-op */ 92 } else if (sscanf(line, "%d\n", &choice) == 0) { 93 printf("Bad input: %s", line); 94 } else if (choice > n || choice <= 0) { 95 printf("Choice %d out of bounds\n", choice); 96 } else { 97 mandoc(choice); 98 } 99 100 free(line); 101 } 102 103 int main(void) { 104 #ifdef __OpenBSD__ 105 /* All unveils for this proc only (not for less) */ 106 if (unveil(MANDIR, "r") == -1) 107 err(1, "unveil"); 108 if (unveil("/dev/tty", "r") == -1) 109 err(1, "unveil"); 110 /* no more unveil's past here! requires pledge*/ 111 if (pledge("stdio rpath", NULL) == -1) 112 err(1, "pledge"); 113 #endif 114 int n = list(); 115 setenv("LESSSECURE", "1", 1); 116 for(;;) 117 prompt(n); 118 return 0; 119 }