alexkarle.com

Source for alexkarle.com
git clone git://git.alexkarle.com/alexkarle.com.git
Log | Files | Refs | README | LICENSE

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 }