Commit message: None
CVE: CVE-2014-10073
CWE: CWE-22
Vulnerability description: The create_response function in server/server.c in Psensor before 1.1.4 allows Directory Traversal because it lacks a check for whether a file is under the webserver directory.

Project: wpitchoune

static int cbk_http_request(void *cls,
			    struct MHD_Connection *connection,
			    const char *url,
			    const char *method,
			    const char *version,
			    const char *upload_data,
			    size_t *upload_data_size,
			    void **ptr)
{
	static int dummy;
	struct MHD_Response *response;
	int ret;
	char *nurl;
	unsigned int resp_code;

	if (strcmp(method, "GET"))
		return MHD_NO;

	if (&dummy != *ptr) {
		/* The first time only the headers are valid, do not
		   respond in the first round... */
		*ptr = &dummy;
		return MHD_YES;
	}

	if (*upload_data_size)
		return MHD_NO;

	*ptr = NULL;		/* clear context pointer */

	log_debug(_("HTTP Request: %s"), url);

	nurl = url_normalize(url);

	pmutex_lock(&mutex);
	response = create_response(nurl, method, &resp_code);
	pmutex_unlock(&mutex);

	ret = MHD_queue_response(connection, resp_code, response);
	MHD_destroy_response(response);

	free(nurl);

	return ret;
}

Project: wpitchoune

create_response_api(const char *nurl, const char *method, unsigned int *rp_code)
{
	struct MHD_Response *resp;
	struct psensor *s;
	char *page = NULL;

	if (!strcmp(nurl, URL_BASE_API_1_1_SENSORS))  {
		page = sensors_to_json_string(server_data.sensors);
#ifdef HAVE_GTOP
	} else if (!strcmp(nurl, URL_API_1_1_SYSINFO)) {
		page = sysinfo_to_json_string(&server_data.psysinfo);
	} else if (!strcmp(nurl, URL_API_1_1_CPU_USAGE)) {
		page = sensor_to_json_string(server_data.cpu_usage);
#endif
	} else if (!strncmp(nurl, URL_BASE_API_1_1_SENSORS,
			    strlen(URL_BASE_API_1_1_SENSORS))
		   && nurl[strlen(URL_BASE_API_1_1_SENSORS)] == '/') {

		const char *sid = nurl + strlen(URL_BASE_API_1_1_SENSORS) + 1;

		s = psensor_list_get_by_id(server_data.sensors, sid);

		if (s)
			page = sensor_to_json_string(s);

	} else if (!strcmp(nurl, URL_API_1_1_SERVER_STOP)) {

		server_stop_requested = 1;
		page = strdup(HTML_STOP_REQUESTED);
	}

	if (page) {
		*rp_code = MHD_HTTP_OK;

		resp = MHD_create_response_from_data(strlen(page), page,
						     MHD_YES, MHD_NO);

		MHD_add_response_header(resp, MHD_HTTP_HEADER_CONTENT_TYPE,
					"application/json");

		return resp;
	}

	return NULL;
}

Project: wpitchoune

static struct MHD_Response *create_response_file(const char *nurl,
						 const char *method,
						 unsigned int *rp_code,
						 const char *fpath)
{
	struct stat st;
	int ret;
	FILE *file;

	ret = stat(fpath, &st);

	if (!ret && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) {
		file = fopen(fpath, "rb");

		if (file) {
			*rp_code = MHD_HTTP_OK;

			if (!st.st_size) {
				fclose(file);
				return MHD_create_response_from_data
					(0, NULL, MHD_NO, MHD_NO);
			}

			return MHD_create_response_from_callback
				(st.st_size,
				 32 * 1024,
				 &file_reader,
				 file,
				 (MHD_ContentReaderFreeCallback)&fclose);

		} else {
			log_err("Failed to open: %s.", fpath);
		}
	}

	return NULL;
}

Project: wpitchoune

file_reader(void *cls, uint64_t pos, char *buf, size_t max)
#else
static int
file_reader(void *cls, uint64_t pos, char *buf, int max)
#endif
{
	FILE *file = cls;

	fseeko(file, pos, SEEK_SET);
	return fread(buf, 1, max, file);
}

Project: wpitchoune

static char *get_path(const char *url, const char *www_dir)
{
	const char *p;
	char *res;

	if (!strlen(url) || !strcmp(url, ".") || !strcmp(url, "/"))
		p = "/index.html";
	else
		p = url;

	res = malloc(strlen(www_dir)+strlen(p)+1);

	strcpy(res, www_dir);
	strcat(res, p);

	return res;
}

Project: wpitchoune

static void print_help(void)
{
	printf(_("Usage: %s [OPTION]...\n"), program_name);

	puts(_("psensor-server is an HTTP server for monitoring hardware "
	       "sensors remotely."));

	puts("");
	puts("Options:");
	puts(_("  -h, --help		display this help and exit\n"
	       "  -v, --version		display version information and exit"));

	puts("");
	puts(_("  -p,--port=PORT	webserver port\n"
	       "  -w,--wdir=DIR		directory containing webserver pages"));

	puts("");
	puts(_("  -d, --debug=LEVEL     "
	       "set the debug level, integer between 0 and 3"));
	puts(_("  -l, --log-file=PATH   set the log file to PATH"));
	puts(_("  --sensor-log-file=PATH set the sensor log file to PATH"));
	puts(_("  --sensor-log-interval=S "
	       "set the sensor log interval to S (seconds)"));

	puts("");
	printf(_("Report bugs to: %s\n"), PACKAGE_BUGREPORT);
	puts("");
	printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
}

Project: wpitchoune

static void print_version(void)
{
	printf("psensor-server %s\n", VERSION);
	printf(_("Copyright (C) %s jeanfi@gmail.com\n"
		 "License GPLv2: GNU GPL version 2 or later "
		 "<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>\n"
		 "This is free software: you are free to change and redistribute it.\n"
		 "There is NO WARRANTY, to the extent permitted by law.\n"),
	       "2010-2012");
}