예제 #1
0
파일: cgi.c 프로젝트: 2asoft/freebsd
/*
 * Scan for indexable paths.
 */
static void
pathgen(struct req *req)
{
	FILE	*fp;
	char	*dp;
	size_t	 dpsz;
	ssize_t	 len;

	if (NULL == (fp = fopen("manpath.conf", "r"))) {
		fprintf(stderr, "%s/manpath.conf: %s\n",
			MAN_DIR, strerror(errno));
		pg_error_internal();
		exit(EXIT_FAILURE);
	}

	dp = NULL;
	dpsz = 0;

	while ((len = getline(&dp, &dpsz, fp)) != -1) {
		if (dp[len - 1] == '\n')
			dp[--len] = '\0';
		req->p = mandoc_realloc(req->p,
		    (req->psz + 1) * sizeof(char *));
		if ( ! validate_urifrag(dp)) {
			fprintf(stderr, "%s/manpath.conf contains "
			    "unsafe path \"%s\"\n", MAN_DIR, dp);
			pg_error_internal();
			exit(EXIT_FAILURE);
		}
		if (NULL != strchr(dp, '/')) {
			fprintf(stderr, "%s/manpath.conf contains "
			    "path with slash \"%s\"\n", MAN_DIR, dp);
			pg_error_internal();
			exit(EXIT_FAILURE);
		}
		req->p[req->psz++] = dp;
		dp = NULL;
		dpsz = 0;
	}
	free(dp);

	if ( req->p == NULL ) {
		fprintf(stderr, "%s/manpath.conf is empty\n", MAN_DIR);
		pg_error_internal();
		exit(EXIT_FAILURE);
	}
}
예제 #2
0
파일: cgi.c 프로젝트: 2asoft/freebsd
static void
format(const struct req *req, const char *file)
{
	struct manoutput conf;
	struct mparse	*mp;
	struct roff_man	*man;
	void		*vp;
	int		 fd;
	int		 usepath;

	if (-1 == (fd = open(file, O_RDONLY, 0))) {
		puts("<P>You specified an invalid manual file.</P>");
		return;
	}

	mchars_alloc();
	mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_BADARG, NULL, req->q.manpath);
	mparse_readfd(mp, fd, file);
	close(fd);

	memset(&conf, 0, sizeof(conf));
	conf.fragment = 1;
	usepath = strcmp(req->q.manpath, req->p[0]);
	mandoc_asprintf(&conf.man, "%s?query=%%N&sec=%%S%s%s%s%s",
	    scriptname,
	    req->q.arch	? "&arch="       : "",
	    req->q.arch	? req->q.arch    : "",
	    usepath	? "&manpath="    : "",
	    usepath	? req->q.manpath : "");

	mparse_result(mp, &man, NULL);
	if (man == NULL) {
		fprintf(stderr, "fatal mandoc error: %s/%s\n",
		    req->q.manpath, file);
		pg_error_internal();
		mparse_free(mp);
		mchars_free();
		return;
	}

	vp = html_alloc(&conf);

	if (man->macroset == MACROSET_MDOC) {
		mdoc_validate(man);
		html_mdoc(vp, man);
	} else {
		man_validate(man);
		html_man(vp, man);
	}

	html_free(vp);
	mparse_free(mp);
	mchars_free();
	free(conf.man);
}
예제 #3
0
파일: cgi.c 프로젝트: mr-justin/freebsd
/*
 * Scan for indexable paths.
 */
static void
pathgen(struct req *req)
{
	FILE	*fp;
	char	*dp;
	size_t	 dpsz;

	if (NULL == (fp = fopen("manpath.conf", "r"))) {
		fprintf(stderr, "%s/manpath.conf: %s\n",
			MAN_DIR, strerror(errno));
		pg_error_internal();
		exit(EXIT_FAILURE);
	}

	while (NULL != (dp = fgetln(fp, &dpsz))) {
		if ('\n' == dp[dpsz - 1])
			dpsz--;
		req->p = mandoc_realloc(req->p,
		    (req->psz + 1) * sizeof(char *));
		dp = mandoc_strndup(dp, dpsz);
		if ( ! validate_urifrag(dp)) {
			fprintf(stderr, "%s/manpath.conf contains "
			    "unsafe path \"%s\"\n", MAN_DIR, dp);
			pg_error_internal();
			exit(EXIT_FAILURE);
		}
		if (NULL != strchr(dp, '/')) {
			fprintf(stderr, "%s/manpath.conf contains "
			    "path with slash \"%s\"\n", MAN_DIR, dp);
			pg_error_internal();
			exit(EXIT_FAILURE);
		}
		req->p[req->psz++] = dp;
	}

	if ( req->p == NULL ) {
		fprintf(stderr, "%s/manpath.conf is empty\n", MAN_DIR);
		pg_error_internal();
		exit(EXIT_FAILURE);
	}
}
예제 #4
0
파일: cgi.c 프로젝트: mr-justin/freebsd
static void
pg_show(struct req *req, const char *fullpath)
{
	char		*manpath;
	const char	*file;

	if ((file = strchr(fullpath, '/')) == NULL) {
		pg_error_badrequest(
		    "You did not specify a page to show.");
		return;
	} 
	manpath = mandoc_strndup(fullpath, file - fullpath);
	file++;

	if ( ! validate_manpath(req, manpath)) {
		pg_error_badrequest(
		    "You specified an invalid manpath.");
		free(manpath);
		return;
	}

	/*
	 * Begin by chdir()ing into the manpath.
	 * This way we can pick up the database files, which are
	 * relative to the manpath root.
	 */

	if (chdir(manpath) == -1) {
		fprintf(stderr, "chdir %s: %s\n",
		    manpath, strerror(errno));
		pg_error_internal();
		free(manpath);
		return;
	}

	if (strcmp(manpath, "mandoc")) {
		free(req->q.manpath);
		req->q.manpath = manpath;
	} else
		free(manpath);

	if ( ! validate_filename(file)) {
		pg_error_badrequest(
		    "You specified an invalid manual file.");
		return;
	}

	resp_begin_html(200, NULL);
	resp_searchform(req);
	resp_show(req, file);
	resp_end_html();
}
예제 #5
0
파일: cgi.c 프로젝트: mr-justin/freebsd
static void
pg_search(const struct req *req)
{
	struct mansearch	  search;
	struct manpaths		  paths;
	struct manpage		 *res;
	char			**argv;
	char			 *query, *rp, *wp;
	size_t			  ressz;
	int			  argc;

	/*
	 * Begin by chdir()ing into the root of the manpath.
	 * This way we can pick up the database files, which are
	 * relative to the manpath root.
	 */

	if (-1 == (chdir(req->q.manpath))) {
		fprintf(stderr, "chdir %s: %s\n",
		    req->q.manpath, strerror(errno));
		pg_error_internal();
		return;
	}

	search.arch = req->q.arch;
	search.sec = req->q.sec;
	search.outkey = "Nd";
	search.argmode = req->q.equal ? ARG_NAME : ARG_EXPR;
	search.firstmatch = 1;

	paths.sz = 1;
	paths.paths = mandoc_malloc(sizeof(char *));
	paths.paths[0] = mandoc_strdup(".");

	/*
	 * Break apart at spaces with backslash-escaping.
	 */

	argc = 0;
	argv = NULL;
	rp = query = mandoc_strdup(req->q.query);
	for (;;) {
		while (isspace((unsigned char)*rp))
			rp++;
		if (*rp == '\0')
			break;
		argv = mandoc_reallocarray(argv, argc + 1, sizeof(char *));
		argv[argc++] = wp = rp;
		for (;;) {
			if (isspace((unsigned char)*rp)) {
				*wp = '\0';
				rp++;
				break;
			}
			if (rp[0] == '\\' && rp[1] != '\0')
				rp++;
			if (wp != rp)
				*wp = *rp;
			if (*rp == '\0')
				break;
			wp++;
			rp++;
		}
	}

	if (0 == mansearch(&search, &paths, argc, argv, &res, &ressz))
		pg_noresult(req, "You entered an invalid query.");
	else if (0 == ressz)
		pg_noresult(req, "No results found.");
	else
		pg_searchres(req, res, ressz);

	free(query);
	mansearch_free(res, ressz);
	free(paths.paths[0]);
	free(paths.paths);
}
예제 #6
0
파일: cgi.c 프로젝트: mr-justin/freebsd
static void
format(const struct req *req, const char *file)
{
	struct mparse	*mp;
	struct mchars	*mchars;
	struct mdoc	*mdoc;
	struct man	*man;
	void		*vp;
	char		*opts;
	enum mandoclevel rc;
	int		 fd;
	int		 usepath;

	if (-1 == (fd = open(file, O_RDONLY, 0))) {
		puts("<P>You specified an invalid manual file.</P>");
		return;
	}

	mchars = mchars_alloc();
	mp = mparse_alloc(MPARSE_SO, MANDOCLEVEL_FATAL, NULL,
	    mchars, req->q.manpath);
	rc = mparse_readfd(mp, fd, file);
	close(fd);

	if (rc >= MANDOCLEVEL_FATAL) {
		fprintf(stderr, "fatal mandoc error: %s/%s\n",
		    req->q.manpath, file);
		pg_error_internal();
		return;
	}

	usepath = strcmp(req->q.manpath, req->p[0]);
	mandoc_asprintf(&opts,
	    "fragment,man=%s?query=%%N&sec=%%S%s%s%s%s",
	    scriptname,
	    req->q.arch	? "&arch="       : "",
	    req->q.arch	? req->q.arch    : "",
	    usepath	? "&manpath="    : "",
	    usepath	? req->q.manpath : "");

	mparse_result(mp, &mdoc, &man, NULL);
	if (NULL == man && NULL == mdoc) {
		fprintf(stderr, "fatal mandoc error: %s/%s\n",
		    req->q.manpath, file);
		pg_error_internal();
		mparse_free(mp);
		mchars_free(mchars);
		return;
	}

	vp = html_alloc(mchars, opts);

	if (NULL != mdoc)
		html_mdoc(vp, mdoc);
	else
		html_man(vp, man);

	html_free(vp);
	mparse_free(mp);
	mchars_free(mchars);
	free(opts);
}
예제 #7
0
파일: cgi.c 프로젝트: mr-justin/freebsd
static void
pg_searchres(const struct req *req, struct manpage *r, size_t sz)
{
	char		*arch, *archend;
	size_t		 i, iuse, isec;
	int		 archprio, archpriouse;
	int		 prio, priouse;
	char		 sec;

	for (i = 0; i < sz; i++) {
		if (validate_filename(r[i].file))
			continue;
		fprintf(stderr, "invalid filename %s in %s database\n",
		    r[i].file, req->q.manpath);
		pg_error_internal();
		return;
	}

	if (1 == sz) {
		/*
		 * If we have just one result, then jump there now
		 * without any delay.
		 */
		printf("Status: 303 See Other\r\n");
		printf("Location: http://%s%s/%s/%s?",
		    HTTP_HOST, scriptname, req->q.manpath, r[0].file);
		http_printquery(req, "&");
		printf("\r\n"
		     "Content-Type: text/html; charset=utf-8\r\n"
		     "\r\n");
		return;
	}

	resp_begin_html(200, NULL);
	resp_searchform(req);
	puts("<DIV CLASS=\"results\">");
	puts("<TABLE>");

	for (i = 0; i < sz; i++) {
		printf("<TR>\n"
		       "<TD CLASS=\"title\">\n"
		       "<A HREF=\"%s/%s/%s?", 
		    scriptname, req->q.manpath, r[i].file);
		http_printquery(req, "&amp;");
		printf("\">");
		html_print(r[i].names);
		printf("</A>\n"
		       "</TD>\n"
		       "<TD CLASS=\"desc\">");
		html_print(r[i].output);
		puts("</TD>\n"
		     "</TR>");
	}

	puts("</TABLE>\n"
	     "</DIV>");

	/*
	 * In man(1) mode, show one of the pages
	 * even if more than one is found.
	 */

	if (req->q.equal) {
		puts("<HR>");
		iuse = 0;
		priouse = 10;
		archpriouse = 3;
		for (i = 0; i < sz; i++) {
			isec = strcspn(r[i].file, "123456789");
			sec = r[i].file[isec];
			if ('\0' == sec)
				continue;
			prio = sec_prios[sec - '1'];
			if (NULL == req->q.arch) {
				archprio =
				    (NULL == (arch = strchr(
					r[i].file + isec, '/'))) ? 3 :
				    (NULL == (archend = strchr(
					arch + 1, '/'))) ? 0 :
				    strncmp(arch, "amd64/",
					archend - arch) ? 2 : 1;
				if (archprio < archpriouse) {
					archpriouse = archprio;
					priouse = prio;
					iuse = i;
					continue;
				}
				if (archprio > archpriouse)
					continue;
			}
			if (prio >= priouse)
				continue;
			priouse = prio;
			iuse = i;
		}
		resp_show(req, r[iuse].file);
	}

	resp_end_html();
}
예제 #8
0
파일: cgi.c 프로젝트: mr-justin/freebsd
int
main(void)
{
	struct req	 req;
	struct itimerval itimer;
	const char	*path;
	const char	*querystring;
	int		 i;

	/* Poor man's ReDoS mitigation. */

	itimer.it_value.tv_sec = 2;
	itimer.it_value.tv_usec = 0;
	itimer.it_interval.tv_sec = 2;
	itimer.it_interval.tv_usec = 0;
	if (setitimer(ITIMER_VIRTUAL, &itimer, NULL) == -1) {
		fprintf(stderr, "setitimer: %s\n", strerror(errno));
		pg_error_internal();
		return(EXIT_FAILURE);
	}

	/* Scan our run-time environment. */

	if (NULL == (scriptname = getenv("SCRIPT_NAME")))
		scriptname = "";

	if ( ! validate_urifrag(scriptname)) {
		fprintf(stderr, "unsafe SCRIPT_NAME \"%s\"\n",
		    scriptname);
		pg_error_internal();
		return(EXIT_FAILURE);
	}

	/*
	 * First we change directory into the MAN_DIR so that
	 * subsequent scanning for manpath directories is rooted
	 * relative to the same position.
	 */

	if (-1 == chdir(MAN_DIR)) {
		fprintf(stderr, "MAN_DIR: %s: %s\n",
		    MAN_DIR, strerror(errno));
		pg_error_internal();
		return(EXIT_FAILURE);
	} 

	memset(&req, 0, sizeof(struct req));
	pathgen(&req);

	/* Next parse out the query string. */

	if (NULL != (querystring = getenv("QUERY_STRING")))
		http_parse(&req, querystring);

	if (req.q.manpath == NULL)
		req.q.manpath = mandoc_strdup(req.p[0]);
	else if ( ! validate_manpath(&req, req.q.manpath)) {
		pg_error_badrequest(
		    "You specified an invalid manpath.");
		return(EXIT_FAILURE);
	}

	if ( ! (NULL == req.q.arch || validate_urifrag(req.q.arch))) {
		pg_error_badrequest(
		    "You specified an invalid architecture.");
		return(EXIT_FAILURE);
	}

	/* Dispatch to the three different pages. */

	path = getenv("PATH_INFO");
	if (NULL == path)
		path = "";
	else if ('/' == *path)
		path++;

	if ('\0' != *path)
		pg_show(&req, path);
	else if (NULL != req.q.query)
		pg_search(&req);
	else
		pg_index(&req);

	free(req.q.manpath);
	free(req.q.arch);
	free(req.q.sec);
	free(req.q.query);
	for (i = 0; i < (int)req.psz; i++)
		free(req.p[i]);
	free(req.p);
	return(EXIT_SUCCESS);
}
예제 #9
0
파일: cgi.c 프로젝트: gokzy/netbsd-src
int
main(void)
{
	struct req	 req;
	struct itimerval itimer;
	const char	*path;
	const char	*querystring;
	int		 i;

	/* Poor man's ReDoS mitigation. */

	itimer.it_value.tv_sec = 2;
	itimer.it_value.tv_usec = 0;
	itimer.it_interval.tv_sec = 2;
	itimer.it_interval.tv_usec = 0;
	if (setitimer(ITIMER_VIRTUAL, &itimer, NULL) == -1) {
		warn("setitimer");
		pg_error_internal();
		return EXIT_FAILURE;
	}

	/*
	 * First we change directory into the MAN_DIR so that
	 * subsequent scanning for manpath directories is rooted
	 * relative to the same position.
	 */

	if (chdir(MAN_DIR) == -1) {
		warn("MAN_DIR: %s", MAN_DIR);
		pg_error_internal();
		return EXIT_FAILURE;
	}

	memset(&req, 0, sizeof(struct req));
	req.q.equal = 1;
	parse_manpath_conf(&req);

	/* Parse the path info and the query string. */

	if ((path = getenv("PATH_INFO")) == NULL)
		path = "";
	else if (*path == '/')
		path++;

	if (*path != '\0') {
		parse_path_info(&req, path);
		if (req.q.manpath == NULL || access(path, F_OK) == -1)
			path = "";
	} else if ((querystring = getenv("QUERY_STRING")) != NULL)
		parse_query_string(&req, querystring);

	/* Validate parsed data and add defaults. */

	if (req.q.manpath == NULL)
		req.q.manpath = mandoc_strdup(req.p[0]);
	else if ( ! validate_manpath(&req, req.q.manpath)) {
		pg_error_badrequest(
		    "You specified an invalid manpath.");
		return EXIT_FAILURE;
	}

	if ( ! (NULL == req.q.arch || validate_urifrag(req.q.arch))) {
		pg_error_badrequest(
		    "You specified an invalid architecture.");
		return EXIT_FAILURE;
	}

	/* Dispatch to the three different pages. */

	if ('\0' != *path)
		pg_show(&req, path);
	else if (NULL != req.q.query)
		pg_search(&req);
	else
		pg_index(&req);

	free(req.q.manpath);
	free(req.q.arch);
	free(req.q.sec);
	free(req.q.query);
	for (i = 0; i < (int)req.psz; i++)
		free(req.p[i]);
	free(req.p);
	return EXIT_SUCCESS;
}
예제 #10
0
파일: cgi.c 프로젝트: gokzy/netbsd-src
static void
pg_searchres(const struct req *req, struct manpage *r, size_t sz)
{
	char		*arch, *archend;
	const char	*sec;
	size_t		 i, iuse;
	int		 archprio, archpriouse;
	int		 prio, priouse;

	for (i = 0; i < sz; i++) {
		if (validate_filename(r[i].file))
			continue;
		warnx("invalid filename %s in %s database",
		    r[i].file, req->q.manpath);
		pg_error_internal();
		return;
	}

	if (req->isquery && sz == 1) {
		/*
		 * If we have just one result, then jump there now
		 * without any delay.
		 */
		printf("Status: 303 See Other\r\n");
		printf("Location: http://%s/%s%s%s/%s",
		    HTTP_HOST, scriptname,
		    *scriptname == '\0' ? "" : "/",
		    req->q.manpath, r[0].file);
		printf("\r\n"
		     "Content-Type: text/html; charset=utf-8\r\n"
		     "\r\n");
		return;
	}

	resp_begin_html(200, NULL);
	resp_searchform(req,
	    req->q.equal || sz == 1 ? FOCUS_NONE : FOCUS_QUERY);

	if (sz > 1) {
		puts("<div class=\"results\">");
		puts("<table>");

		for (i = 0; i < sz; i++) {
			printf("<tr>\n"
			       "<td class=\"title\">\n"
			       "<a href=\"/%s%s%s/%s",
			    scriptname, *scriptname == '\0' ? "" : "/",
			    req->q.manpath, r[i].file);
			printf("\">");
			html_print(r[i].names);
			printf("</a>\n"
			       "</td>\n"
			       "<td class=\"desc\">");
			html_print(r[i].output);
			puts("</td>\n"
			     "</tr>");
		}

		puts("</table>\n"
		     "</div>");
	}

	/*
	 * In man(1) mode, show one of the pages
	 * even if more than one is found.
	 */

	if (req->q.equal || sz == 1) {
		puts("<hr>");
		iuse = 0;
		priouse = 20;
		archpriouse = 3;
		for (i = 0; i < sz; i++) {
			sec = r[i].file;
			sec += strcspn(sec, "123456789");
			if (sec[0] == '\0')
				continue;
			prio = sec_prios[sec[0] - '1'];
			if (sec[1] != '/')
				prio += 10;
			if (req->q.arch == NULL) {
				archprio =
				    ((arch = strchr(sec + 1, '/'))
					== NULL) ? 3 :
				    ((archend = strchr(arch + 1, '/'))
					== NULL) ? 0 :
				    strncmp(arch, "amd64/",
					archend - arch) ? 2 : 1;
				if (archprio < archpriouse) {
					archpriouse = archprio;
					priouse = prio;
					iuse = i;
					continue;
				}
				if (archprio > archpriouse)
					continue;
			}
			if (prio >= priouse)
				continue;
			priouse = prio;
			iuse = i;
		}
		resp_show(req, r[iuse].file);
	}

	resp_end_html();
}