=================================================================== RCS file: /cvs/mandoc/cgi.c,v retrieving revision 1.141 retrieving revision 1.149 diff -u -p -r1.141 -r1.149 --- mandoc/cgi.c 2016/09/12 00:06:20 1.141 +++ mandoc/cgi.c 2017/03/15 10:17:29 1.149 @@ -1,7 +1,7 @@ -/* $Id: cgi.c,v 1.141 2016/09/12 00:06:20 schwarze Exp $ */ +/* $Id: cgi.c,v 1.149 2017/03/15 10:17:29 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons - * Copyright (c) 2014, 2015, 2016 Ingo Schwarze + * Copyright (c) 2014, 2015, 2016, 2017 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -21,7 +21,9 @@ #include #include +#if HAVE_ERR #include +#endif #include #include #include @@ -74,6 +76,7 @@ static void pg_error_badrequest(const char *); static void pg_error_internal(void); static void pg_index(const struct req *); static void pg_noresult(const struct req *, const char *); +static void pg_redirect(const struct req *, const char *); static void pg_search(const struct req *); static void pg_searchres(const struct req *, struct manpage *, size_t); @@ -113,7 +116,7 @@ static const char *const sec_names[] = { static const int sec_MAX = sizeof(sec_names) / sizeof(char *); static const char *const arch_names[] = { - "amd64", "alpha", "armv7", + "amd64", "alpha", "armv7", "arm64", "hppa", "i386", "landisk", "loongson", "luna88k", "macppc", "mips64", "octeon", "sgi", "socppc", "sparc64", @@ -351,13 +354,12 @@ resp_begin_html(int code, const char *msg) printf("\n" "\n" "\n" - "\n" - "\n" + " \n" - "%s\n" + " %s\n" "\n" - "\n" - "\n", + "\n", CSS_DIR, CUSTOMIZE_TITLE); resp_copy(MAN_DIR "/header.html"); @@ -378,16 +380,14 @@ resp_searchform(const struct req *req, enum focus focu { int i; - puts(""); - printf("
\n" - "
\n" - "
\n" - "Manual Page Search Parameters\n", + printf("\n" + "
\n" + " Manual Page Search Parameters\n", scriptname); /* Write query input box. */ - printf("q.query != NULL) html_print(req->q.query); printf( "\" size=\"40\""); @@ -397,45 +397,46 @@ resp_searchform(const struct req *req, enum focus focu /* Write submission buttons. */ - printf( "\n" - "\n
\n"); + " \n" + "
\n"); /* Write section selector. */ - puts(""); for (i = 0; i < sec_MAX; i++) { - printf("\n", sec_names[i]); } - puts(""); + puts(" "); /* Write architecture selector. */ - printf( ""); + puts(" "); /* Write manpath selector. */ if (req->psz > 1) { - puts(""); for (i = 0; i < (int)req->psz; i++) { - printf(""); } - puts(""); + puts(" "); } - puts("
\n" - "\n" - "
"); - puts(""); + puts(" \n" + ""); } static int @@ -498,9 +497,9 @@ pg_index(const struct req *req) resp_searchform(req, FOCUS_QUERY); printf("

\n" "This web interface is documented in the\n" - "man.cgi(8)\n" + "man.cgi(8)\n" "manual, and the\n" - "apropos(1)\n" + "apropos(1)\n" "manual explains the query syntax.\n" "

\n", scriptname, *scriptname == '\0' ? "" : "/", @@ -542,6 +541,23 @@ pg_error_internal(void) } static void +pg_redirect(const struct req *req, const char *name) +{ + printf("Status: 303 See Other\r\n"); + printf("Location: http://%s/", HTTP_HOST); + if (*scriptname != '\0') + printf("%s/", scriptname); + if (strcmp(req->q.manpath, req->p[0])) + printf("%s/", req->q.manpath); + if (req->q.arch != NULL) + printf("%s/", req->q.arch); + printf("%s", name); + if (req->q.sec != NULL) + printf(".%s", req->q.sec); + printf("\r\nContent-Type: text/html; charset=utf-8\r\n\r\n"); +} + +static void pg_searchres(const struct req *req, struct manpage *r, size_t sz) { char *arch, *archend; @@ -580,27 +596,21 @@ pg_searchres(const struct req *req, struct manpage *r, req->q.equal || sz == 1 ? FOCUS_NONE : FOCUS_QUERY); if (sz > 1) { - puts("
"); - puts(""); - + puts("
"); for (i = 0; i < sz; i++) { - printf("\n" - "\n" - "\n" + " \n" - ""); + puts("\n" + " "); } - - puts("
\n" - "\n" + " " + "", scriptname, *scriptname == '\0' ? "" : "/", req->q.manpath, r[i].file); - printf("\">"); html_print(r[i].names); - printf("\n" - ""); + printf(""); html_print(r[i].output); - puts("
\n" - "
"); + puts(""); } /* @@ -809,6 +819,7 @@ resp_format(const struct req *req, const char *file) memset(&conf, 0, sizeof(conf)); conf.fragment = 1; + conf.style = mandoc_strdup(CSS_DIR "/mandoc.css"); usepath = strcmp(req->q.manpath, req->p[0]); mandoc_asprintf(&conf.man, "/%s%s%%N.%%S", usepath ? req->q.manpath : "", usepath ? "/" : ""); @@ -836,6 +847,7 @@ resp_format(const struct req *req, const char *file) mparse_free(mp); mchars_free(); free(conf.man); + free(conf.style); } static void @@ -962,9 +974,13 @@ pg_search(const struct req *req) } } - if (0 == mansearch(&search, &paths, argc, argv, &res, &ressz)) + res = NULL; + ressz = 0; + if (req->isquery && req->q.equal && argc == 1) + pg_redirect(req, argv[0]); + else if (mansearch(&search, &paths, argc, argv, &res, &ressz) == 0) pg_noresult(req, "You entered an invalid query."); - else if (0 == ressz) + else if (ressz == 0) pg_noresult(req, "No results found."); else pg_searchres(req, res, ressz); @@ -983,6 +999,22 @@ main(void) const char *path; const char *querystring; int i; + +#if HAVE_PLEDGE + /* + * The "rpath" pledge could be revoked after mparse_readfd() + * if the file desciptor to "/footer.html" would be opened + * up front, but it's probably not worth the complication + * of the code it would cause: it would require scattering + * pledge() calls in multiple low-level resp_*() functions. + */ + + if (pledge("stdio rpath", NULL) == -1) { + warn("pledge"); + pg_error_internal(); + return EXIT_FAILURE; + } +#endif /* Poor man's ReDoS mitigation. */