diff options
Diffstat (limited to 'main.c')
-rwxr-xr-x | main.c | 171 |
1 files changed, 139 insertions, 32 deletions
@@ -13,29 +13,17 @@ #/ - No JavaScript #/ - No external dependencies #/ - No dynamic memory management -#/ - Simple bootstrap script -#/ - Not a single LLM-generated line of code #/ -#/ NOTE +#/ NOTE: At the start of this file you can see a shell script +#/ that will compile and install the program into `/srv/` #/ -#/ - At the start of this file you can see a shell script -#/ that will compile and install the program into `/srv/` +#/ To-Do list #/ -#/ TODO -#/ -#/ - CGI program -#/ - Hierarchical tags. -#/ - Blacklist and throttling. -#/ - Wrap other CGI programs. -#/ - CI terminal -#/ - Convay's Game of Life with `<meta http-equiv="refresh" content="1" >` -#/ - Bootstrap script -#/ - ssh -#/ - git config -#/ - highlight -#/ - tor, onion service -#/ - daemons -#/ - ufw +#/ - Hierarchical tags. +#/ - Blacklist and throttling. +#/ - Redirects for cgit and git-http-backend. +#/ - CI terminal. +#/ - Convay's Game of Life with `<meta http-equiv="refresh" content="1" >` #/ #/ ================================================================ @@ -86,6 +74,8 @@ exit $? # */ #define FORM_NAME "submit" #define FORM_ITEM_DATA "data" +#define CGI_CGIT "/usr/lib/cgit/cgit.cgi" + enum { DEFAULT_SCALE = 100, DEFAULT_WIDTH = 42, @@ -508,7 +498,7 @@ static Redirect redirects[] = { }, { .alias = "/juliaset", .url = "/static/plain/juliaset/index.htm", - .cgi = "/usr/lib/cgit/cgit.cgi", + .cgi = CGI_CGIT, .replace_headers = (Replace_Header[]) { { .name = "Content-Type", .value = "text/html; charset=UTF-8", }, { .name = "X-Content-Type-Options", .value = NULL, }, @@ -2446,29 +2436,38 @@ i32 run_cgi(c8 const *cgi, c8 *const *argv, c8 *const *envp) { signal(SIGCHLD, SIG_IGN); signal(SIGALRM, SIG_IGN); + i32 pipe_in[2]; i32 pipe_out[2]; - if (pipe(pipe_out) == -1) + if (pipe(pipe_in) == -1) return 1; + if (pipe(pipe_out) == -1) + return 2; if (fcntl(pipe_out[1], F_SETFL, O_NONBLOCK) == -1) - return 2; + return 3; pid_t id = fork(); switch (id) { case -1: - return 3; + return 4; case 0: + if (dup2(pipe_in[0], STDIN_FILENO) == -1) + return 5; if (dup2(pipe_out[1], STDOUT_FILENO) == -1) - return 4; + return 6; + close(pipe_in[0]); + close(pipe_in[1]); close(pipe_out[0]); close(pipe_out[1]); execve(cgi, argv, envp); - return 5; + // No return. + + return 7; default:; } @@ -2486,7 +2485,7 @@ i32 run_cgi(c8 const *cgi, c8 *const *argv, c8 *const *envp) { i64 n = read(pipe_out[0], cgi_output, sizeof cgi_output - 1); if (n <= 0) - return 6; + return 8; cgi_output[n] = '\0'; cgi_output_size = n; @@ -2952,6 +2951,21 @@ b8 str_eq_with_slash(c8 const *a, c8 const *b) { return 0; } +b8 str_eq_prefix(c8 const *a, c8 const *b) { + for (; *b != '\0'; ++a, ++b) + if (*a != *b) + return 0; + return 1; +} + +b8 str_eq_postfix(c8 const *a, c8 const *b) { + i64 a_len = strlen(a); + i64 b_len = strlen(b); + if (a_len >= b_len) + return memcmp(a + (a_len - b_len), b, b_len) == 0; + return 0; +} + i32 check_color(i32 c) { if (c >= 0 && c < COLORS_MAX) return c; @@ -3002,6 +3016,44 @@ void skip_spaces(c8 const *s, i32 *n) { } } +b8 knock_knock_cookie(c8 const *cookie) { + c8 knock_knock[] = "knock=knock"; + + { + c8 const *val = cookie; + c8 const *val_end = NULL; + + while (*val != '\0') { + while (*val == ' ' || *val == ';') ++val; + val_end = val; + while (*val_end != ';' && *val_end != '\0') ++val_end; + + if (memcmp(val, knock_knock, sizeof knock_knock - 1) == 0) + return 1; + } + } + + printf("Status: 200 OK\r\n"); + printf("Set-Cookie: %s; Path=/; SameSite=Lax; Expires=", knock_knock); + print_time_gmt(6 * SECONDS_IN_MONTH); + printf("; HttpOnly\r\n"); + printf("Cross-Origin-Opener-Policy: same-origin\r\n"); + printf("Cross-Origin-Embedder-Policy: require-corp\r\n"); + printf("Content-Type: text/html\r\n"); + printf("\r\n"); + + printf("<!DOCTYPE html><html><head>"); + printf("<meta http-equiv=\"refresh\" content=\"1\" >"); + printf("<meta charset='utf-8'>"); + printf("<meta name='viewport' content='width=device-width,initial-scale=1'>"); + printf("<link rel='icon' type='image/gif' href='/favicon.gif'>"); + printf("<title> Knock-knock </title>"); + printf("</head><body></body>"); + printf("\r\n"); + + return 0; +} + void setup_theme_cookie(c8 const *cookie, c8 const *query) { // Parse cookie values // @@ -3225,7 +3277,7 @@ i32 main(i32 argc, c8 **argv) { return 0; } - // TODO Check blacklist and throttling + // TODO: Check blacklist and throttling. if (0) { printf("Status: 400 Forbidden\r\n"); @@ -3237,6 +3289,8 @@ i32 main(i32 argc, c8 **argv) { return 0; } + // Redirects. + i32 doc = DOC_404; for (i64 i = 0; i < (i64)(sizeof redirects / sizeof *redirects); ++i) @@ -3341,6 +3395,61 @@ i32 main(i32 argc, c8 **argv) { } } + // Knock-knock. + + if (!knock_knock_cookie(http_cookie)) + return 0; + + // cgit hooks. + + if (str_eq_prefix(document_uri, "/git/")) { + static c8 buf_path [4096] = {0}; + static c8 buf_query [4096] = {0}; + + snprintf(buf_path, sizeof buf_path - 1, "PATH_INFO=%s", document_uri + 4); + snprintf(buf_query, sizeof buf_query - 1, "QUERY_STRING=%s", query_string); + + c8 *argv[] = { CGI_CGIT, NULL }; + c8 *envp[] = { buf_path, buf_query, NULL }; + + i32 s = run_cgi(CGI_CGIT, argv, envp); + if (s != 0) { + printf("Status: 500 Internal Server Error %d\r\n", s); + return 0; + } + + fflush(stdout); + i32 written = write(STDOUT_FILENO, cgi_output, cgi_output_size); + (void) written; + + return 0; + } + + if (str_eq_postfix(document_uri, ".git")) { + static c8 buf_path [4096] = {0}; + static c8 buf_query [4096] = {0}; + + snprintf(buf_path, sizeof buf_path - 1, "PATH_INFO=%s", document_uri + 4); + snprintf(buf_query, sizeof buf_query - 1, "QUERY_STRING=%s", query_string); + + c8 *argv[] = { CGI_CGIT, NULL }; + c8 *envp[] = { buf_path, buf_query, NULL }; + + i32 s = run_cgi(CGI_CGIT, argv, envp); + if (s != 0) { + printf("Status: 500 Internal Server Error %d\r\n", s); + return 0; + } + + fflush(stdout); + i32 written = write(STDOUT_FILENO, cgi_output, cgi_output_size); + (void) written; + + return 0; + } + + // Normal HTML gen. + for (i64 i = 0; i < (i64)(sizeof locs / sizeof *locs); ++i) if (strcmp(request_method, locs[i].method) == 0 && str_eq_with_slash(document_uri, locs[i].uri)) { @@ -3368,10 +3477,8 @@ i32 main(i32 argc, c8 **argv) { printf("<!DOCTYPE html><html><head>"); { printf("<meta charset='utf-8'>"); - printf("<meta name='viewport' " - "content='width=device-width,initial-scale=1'>"); - printf( - "<link rel='icon' type='image/gif' href='/favicon.gif'>"); + printf("<meta name='viewport' content='width=device-width,initial-scale=1'>"); + printf("<link rel='icon' type='image/gif' href='/favicon.gif'>"); printf("<title> %s </title>", docs[doc].title); printf("<style>"); for (i64 i = 0; i < (i64)(sizeof fonts / sizeof *fonts); ++i) |