aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSami Littow <sami.littow@qt.io>2023-04-14 08:54:38 +0300
committerSami Littow <sami.littow@qt.io>2023-04-19 14:36:08 +0300
commit481ae1cb9e52dfe198030e9a4a6e562005f04ca7 (patch)
tree4365c32ac61766da8d539c4eb60a31a4edcd900d
parentb8e7c76ea05ab2ab1dbec0efe547ee2ff259e374 (diff)
Fix of a bug where daemon grants non-valid licenseHEADdev
(clitoolhandler.h) - Server response validity was only checked when requesting longterm reservation - Could have exploited with telnet - Server response JSON status field check moved to the beginning of method (HttpClient, Licenser classes) - Pass the REST endpoint to the HTTP client per request, rather than trying to guess it in HTTP client Change-Id: I13d05b33f1032a91d393e7315552f1b9d391142d Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Arttu Tarkiainen <arttu.tarkiainen@qt.io>
-rw-r--r--src/libs/qlicenseservice/clienthandler.cpp5
-rw-r--r--src/libs/qlicenseservice/daemon_clients/clitoolhandler.h48
-rw-r--r--src/libs/qlicenseservice/httpclient.cpp47
-rw-r--r--src/libs/qlicenseservice/httpclient.h16
-rw-r--r--src/libs/qlicenseservice/licenser.cpp11
-rw-r--r--src/libs/qlicenseservice/request.h1
6 files changed, 52 insertions, 76 deletions
diff --git a/src/libs/qlicenseservice/clienthandler.cpp b/src/libs/qlicenseservice/clienthandler.cpp
index fbeab7b..863384e 100644
--- a/src/libs/qlicenseservice/clienthandler.cpp
+++ b/src/libs/qlicenseservice/clienthandler.cpp
@@ -62,8 +62,10 @@ int ClientHandler::parseRequest()
m_request.reqType = RequestType::no_request;
if (cmd == LICENSE_REQUEST_CMD) {
m_request.reqType = RequestType::license_request;
+ m_request.accessPoint = m_settings.get("reservation_access_point");
} else if (cmd ==PERMANENT_REQUEST_CMD) {
m_request.reqType = RequestType::long_term_request;
+ m_request.accessPoint = m_settings.get("permanent_access_point");
// find either 'add' or 'remove'
if (params.size() > 0) {
if (params[0] != OP_ADD_RESERVATION && params[0] != OP_REMOVE_RESERVATION) {
@@ -80,8 +82,7 @@ int ClientHandler::parseRequest()
params.erase(params.begin());
} else if (cmd == SERVER_VERSION_CMD) {
m_request.reqType = RequestType::server_version;
- buildRequestJson();
- return 0;
+ m_request.accessPoint = m_settings.get("version_query_access_point");
} else if (cmd == DAEMON_VERSION_CMD) {
m_request.reqType = RequestType::daemon_version;
} else if (cmd == RESERVATION_QUERY_CMD) {
diff --git a/src/libs/qlicenseservice/daemon_clients/clitoolhandler.h b/src/libs/qlicenseservice/daemon_clients/clitoolhandler.h
index ceeefc0..021d958 100644
--- a/src/libs/qlicenseservice/daemon_clients/clitoolhandler.h
+++ b/src/libs/qlicenseservice/daemon_clients/clitoolhandler.h
@@ -45,37 +45,33 @@ class CliToolHandler : public virtual ClientHandler {
JsonHandler json(response);
std::stringstream ss;
- if (m_request.reqType == RequestType::long_term_request) {
- // long-term request: Have "message" field from response JSON directly as a reply to the user
- response = json.get("message");
- if (json.get("status") != "true" ) {
- if (response == "License fully reserved") {
- response = replyString[e_license_pool_full];
- } else if (response.find("cannot be early released") != std::string::npos) {
- response = replyString[e_no_permanent_to_release];
- } else {
- response = replyString[e_license_rejected];
- }
- // Do not touch the license file, just return
- return 1;
- }
- } else if (m_request.reqType == RequestType::server_version) {
+ if (m_request.reqType == RequestType::server_version) {
response = "Qt License Server v";
response += json.get("version");
- return 0; // Do not touch cached license files pls.
+ return 0;
}
- ss << replyString[e_license_granted];
- ss << " expiry_date=" << json.get("expiry_date");
- ss << " license_id=" << json.get("license_number");
- ss << " reservation_id=" << json.get("reservation_id");
- response = ss.str();
- // Add timestamp into license JSON
- json.add("last_timestamp", utils::getTimestampNow());
+ if (json.get("status") != "true" ) {
+ if (response == "License fully reserved") {
+ response = replyString[e_license_pool_full];
+ } else if (response.find("cannot be early released") != std::string::npos) {
+ response = replyString[e_no_permanent_to_release];
+ } else {
+ response = replyString[e_license_rejected];
+ }
+ // Do not touch the license file, just return
+ return 1;
+ } else if (m_request.reqType == RequestType::long_term_request) {
+ // long-term request: Have "message" field from response JSON directly as a reply to the user
+ response = json.get("message");
- int result = utils::writeToFile(m_request.licenseFile, json.dump(4));
- if (result != 0) {
- std::cout << "ERROR saving license file: '" << m_request.licenseFile << "': " << strerror(result) << std::endl;
+ // Add timestamp into license JSON
+ json.add("last_timestamp", utils::getTimestampNow());
+
+ int result = utils::writeToFile(m_request.licenseFile, json.dump(4));
+ if (result != 0) {
+ std::cout << "ERROR saving license file: '" << m_request.licenseFile << "': " << strerror(result) << std::endl;
+ }
}
return 0;
}
diff --git a/src/libs/qlicenseservice/httpclient.cpp b/src/libs/qlicenseservice/httpclient.cpp
index 7f5d1fc..8d07674 100644
--- a/src/libs/qlicenseservice/httpclient.cpp
+++ b/src/libs/qlicenseservice/httpclient.cpp
@@ -16,45 +16,34 @@ size_t WriteCallback(char *contents, size_t size, size_t nmemb, void *userp)
return size * nmemb;
}
-HttpClient::HttpClient( const std::string &serverUrl,
- const std::string &requestAccessPoint,
- const std::string &permanentAccessPoint,
- const std::string &versionAccessPoint) :
- m_serverUrl(serverUrl),
- m_requestAccessPoint(requestAccessPoint),
- m_permanentAccessPoint(permanentAccessPoint),
- m_versionAccessPoint(versionAccessPoint)
+HttpClient::HttpClient(const std::string &serverUrl)
+ : m_serverUrl(serverUrl)
{
m_userAgent += DAEMON_VERSION;
}
-int HttpClient::sendRequest(std::string &reply, const std::string &payload,
- const std::string &server, const std::string &authKey)
+int HttpClient::sendAndReceive(std::string &reply, const std::string &payload,
+ const std::string &accessPoint, const std::string &server,
+ const std::string &authKey)
{
+ if (accessPoint.empty()) {
+ std::cout << "[HttpClient] error: No server endpoint given\n";
+ return 1;
+ }
HttpRequest request;
- m_lastError = "No errors";
-
- /* specify URL to POST */
- request.url = server;
- request.payload = payload;
+ // specify URL
if (server.empty()) {
// If server URL is not given as param, we use the default
request.url = m_serverUrl;
}
+ request.url += accessPoint;
+ request.payload = payload;
+
if (!authKey.empty()) {
- // normal request
- request.url += m_requestAccessPoint;
+ // Add auth key in headers
std::string auth = "Authorization: " + authKey;
request.headers = curl_slist_append(request.headers, auth.c_str());
- } else {
- if (payload.empty()) {
- // version query
- request.url += m_versionAccessPoint;
- } else {
- // permanentrequest
- request.url += m_permanentAccessPoint;
- }
}
std::string agent = "User-Agent: " + m_userAgent;
@@ -73,13 +62,11 @@ int HttpClient::sendRequest(std::string &reply, const std::string &payload,
retVal = 1;
}
} catch(...) {
- m_lastError = "Connection failed";
+ std::cout << "Connection failed\n";
retVal = 1;
}
if (retVal == 0) {
std::cout << request.reply.length() << " bytes retrieved from license server\n";
- } else {
- std::cout << m_lastError << std::endl;
}
/* cleanup curl stuff */
@@ -108,7 +95,7 @@ int HttpClient::doRequest(CURL *curl, HttpRequest &request)
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request.payload.c_str());
}
else {
- curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, 1); // for server ping
}
if (curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL) != CURLE_OK) {
std::cout << "Warning! No SSL support available\n";
@@ -122,7 +109,7 @@ int HttpClient::doRequest(CURL *curl, HttpRequest &request)
// check for errors
if (res != CURLE_OK) {
std::cout << "HTTP transfer failed, URL: " << request.url << std::endl;
- m_lastError = curl_easy_strerror(res);
+ std::cout << curl_easy_strerror(res) << std::endl;
return 1;
}
request.reply = readBuffer;
diff --git a/src/libs/qlicenseservice/httpclient.h b/src/libs/qlicenseservice/httpclient.h
index 13d2478..9df41c6 100644
--- a/src/libs/qlicenseservice/httpclient.h
+++ b/src/libs/qlicenseservice/httpclient.h
@@ -38,22 +38,16 @@ struct HttpRequest {
class HttpClient
{
public:
- explicit HttpClient(const std::string &serverUrl,
- const std::string &requestAccessPoint,
- const std::string &permanentccessPoint,
- const std::string &versionAccessPoint);
+ explicit HttpClient(const std::string &serverUrl);
+
~HttpClient() {}
- int sendRequest(std::string &reply, const std::string &payload,
- const std::string &server, const std::string &authKey="");
- std::string error() { return m_lastError; }
+ int sendAndReceive(std::string &reply, const std::string &payload,
+ const std::string &accessPoint, const std::string &server,
+ const std::string &authKey="");
private:
std::string m_serverUrl;
- std::string m_requestAccessPoint;
- std::string m_permanentAccessPoint;
- std::string m_versionAccessPoint;
std::string m_userAgent = "License daemon / ";
- std::string m_lastError;
int doRequest(CURL *curl, HttpRequest &request);
};
diff --git a/src/libs/qlicenseservice/licenser.cpp b/src/libs/qlicenseservice/licenser.cpp
index 9094bd7..df85f4e 100644
--- a/src/libs/qlicenseservice/licenser.cpp
+++ b/src/libs/qlicenseservice/licenser.cpp
@@ -31,10 +31,7 @@ Licenser::Licenser(uint16_t tcpPort, const std::string &settingsPath)
}
m_mocInterval = utils::strToInt(m_settings->get("moc_renewal_interval")) * SECS_IN_HOUR;
// Start the HTTP client
- m_http = new HttpClient(m_settings->get("server_addr"),
- m_settings->get("reservation_access_point"),
- m_settings->get("permanent_access_point"),
- m_settings->get("version_query_access_point"));
+ m_http = new HttpClient(m_settings->get("server_addr"));
// Start the TCP/IP server
m_tcpServer = new TcpServer(tcpPort);
if (!m_tcpServer->init()) {
@@ -149,7 +146,6 @@ int Licenser::listen()
if (m_floatingClients.size() > 0) {
checkTasksDue();
}
- std::cout << "Current clients in cache: " << m_floatingClients.size() << std::endl;
return 0;
}
@@ -214,7 +210,6 @@ ClientHandler *Licenser::parseInputAndCreateCLient(uint16_t socketId, const std:
int Licenser::sendServerRequest(const RequestInfo &request, std::string &reply)
{
std::string auth;
- std::cout << "Payload: " << request.payload << std::endl;
// Generate auth hash for HTTP headers
std::string hash;
@@ -223,7 +218,9 @@ int Licenser::sendServerRequest(const RequestInfo &request, std::string &reply)
auth = "apikey " + hash;
// Send the request
- if (m_http->sendRequest(reply, request.payload, request.serverAddr, auth) != 0) {
+ if (m_http->sendAndReceive(reply, request.payload,
+ request.accessPoint,
+ request.serverAddr, auth) != 0) {
return e_bad_connection;
}
return e_got_response;
diff --git a/src/libs/qlicenseservice/request.h b/src/libs/qlicenseservice/request.h
index 7533e4e..1668c92 100644
--- a/src/libs/qlicenseservice/request.h
+++ b/src/libs/qlicenseservice/request.h
@@ -46,6 +46,7 @@ struct RequestInfo {
std::string email;
std::string payload;
std::string serverAddr;
+ std::string accessPoint;
uint64_t startTimestamp = 0; // used by QA-Tools only
uint64_t stopTimestamp = 0; // used by QA-Tools only
std::string runnerType; // "qa_tester" || "qa_exe", used by QA-Tools only