#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include #include "config.h" static const char *badchars = "\\?%:|\"<> "; int writable(char *path) { struct stat s; if(!stat(path, &s)) { if(S_ISREG(s.st_mode)) return !access(path, W_OK); else if(S_ISDIR(s.st_mode)) return 0; } char *dir = dirname(strdup(path)); if(!stat(dir, &s)) { if(S_ISDIR(s.st_mode)) return !access(dir, W_OK); } return 0; } void head(char *page, char *link, char *what) { printf("Content-Type: text/html; charset=utf-8\n\n"); printf("\n"); printf("%s ยท %s\n", title, page); printf("\n", base); if(link && what) printf("

%s

", what, link, page); else printf("

%s

", page); } void foot(int file) { printf("
\n"); printf("

"); for(int i = 0; *links[i]; i++) printf("%s ", script, links[i][1], links[i][0]); if(!file) return; printf(""); printf("%s ", id); printf("text/plain"); printf("\n"); } char *clean(char *p) { char *dup = strdup(basename(p)); char *x = dup; while(*x) { if(*x == '-') *x = ' '; x++; } return dup; } int legit(char *page) { if(!page) return 0; if(!strcmp(page, "/")) return 0; if(strstr(page, "..")) return 0; if(strcspn(page, badchars) < strlen(page)) return 0; return 1; } int problem(int status, char *message) { printf("Status: %d\n", status); printf("Content-Type: text/plain\n\n"); printf("%s\n", message); return 1; } int redirect(char *path) { printf("Status: 303\n"); if(*path == '?') printf("Location: %s\n\n", path); else printf("Location: %s/%s\n\n", script, path); return 0; } int unauthorized(int status) { printf("Status: %d\n", status); if(status == 401) printf("WWW-Authenticate: Basic realm='Kya'\n"); printf("Content-Type: text/plain; charset=utf-8\n\n"); printf("No.\n"); return 1; } int edit(char *path) { if(!writable(path)) return unauthorized(403); FILE *fp = fopen(path, "r"); char *page = clean(path); fp ? head(page, path, "vis") : head(page, NULL, NULL); char buffer[sysconf(_SC_PAGESIZE)]; printf("

\n"); printf("

\n"); printf("

"); printf("

"); foot(1); if(fp) fclose(fp); return 0; } int post(char *path) { char *header, *data; int clen; header = getenv("CONTENT_LENGTH"); if(!header) return redirect(path); clen = atoi(header); data = calloc(1, clen + 1); fread(data, clen, 1, stdin); if(strncmp(data, "text=", 5)) return redirect(path); FILE *fp = fopen(path, "w"); if(!fp) return redirect(path); fwrite(data + 5, clen - 5, 1, fp); fputc('\0', fp); fclose(fp); return redirect(path); } int list(char *raw, int dir) { int len = strlen(raw); char *pattern = malloc(len + 3); if(dir) snprintf(pattern, len + 3, "%s/*", raw); else snprintf(pattern, len + 1, "%s", raw); glob_t res; if(glob(pattern, GLOB_MARK, NULL, &res)) { head("ingen treff", NULL, NULL); foot(0); return 0; } head("treff", NULL, NULL); char *path; printf("
    "); for(int i = 0; i < res.gl_pathc; i++) { path = res.gl_pathv[i]; printf("
  • %s", script, path, path); } printf("
"); foot(0); free(pattern); return 0; } int text(char *path) { FILE *fp = fopen(path, "r"); if(fp) { char buffer[sysconf(_SC_PAGESIZE)]; printf("Content-Type: text/plain; charset=utf-8\n\n"); while(fgets(buffer, sizeof(buffer), fp)) printf("%s", buffer); } fclose(fp); return 0; } int view(char *path) { struct stat s; stat(path, &s); if(S_ISDIR(s.st_mode)) return list(path, 1); FILE *fp = fopen(path, "r"); if(!fp) return redirect("?e"); char *page = clean(path); writable(path) ? head(page, "?e", "rediger") : head(page, NULL, NULL); marxup(fp, stdout, NULL); foot(1); return 0; } int main(int argc, char **argv) { char *method = getenv("REQUEST_METHOD"); char *page = getenv("PATH_INFO"); char *query = getenv("QUERY_STRING"); if(!page && argc > 1) page = argv[1]; if(!query && argc > 2) query = argv[2]; if(!method) method = "GET"; if(!script) script = getenv("SCRIPT_NAME"); if(!script) script = ""; if(!base) base = strdup(dirname(strdup(script))); if(authenticate && !(id = authenticate())) return unauthorized(401); if(!legit(page++)) return redirect("home"); setenv("MARXUP_HEADER", "2", 1); setenv("MARXUP_PREFIX", base, 1); if(chdir("pages")) return problem(404, "Not found"); if(!strncmp(method, "POST", 4)) return post(page); while(query && *query) { switch(*query) { case 'e': return edit(page); case 't': return text(page); // case 'p': return } query++; } if(strchr(page, '*')) return list(page, 0); return view(page); }