sandboxed-api/oss-internship-2020/curl/examples/example3.cc
Christian Blichmann 3a95d9df41 Fix cURL example
Due to a naming mixup in `oss-internship-2020/curl/CMakeLists.txt`, the
necessary `WriteToMemory()` callback was not linked into the sandboxee,
leading to a segfault in the sandboxee when trying to run the
tests/examples.

As another issue, cURL seems to call `sysinfo` and `rt_sigaction` in
recent versions and with recent libc.

Drive-by changes:
- Use the SAPI status macros instead of manually checking `absl::Status`
- Put tests in namespace
- Some Google C++-style fixes
- Start the mock test server only once per test suite

Fixes #72 for cURL.

Signed-off-by: Christian Blichmann <cblichmann@google.com>
2021-01-25 17:01:54 +01:00

185 lines
6.2 KiB
C++

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Sandboxed version of simplessl.c
// HTTPS GET request
#include <cstdlib>
#include "../sandbox.h" // NOLINT(build/include)
namespace {
class CurlSapiSandboxEx3 : public curl::CurlSapiSandbox {
public:
CurlSapiSandboxEx3(std::string ssl_certificate, std::string ssl_key,
std::string ca_certificates)
: ssl_certificate(ssl_certificate),
ssl_key(ssl_key),
ca_certificates(ca_certificates) {}
private:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
// Add the syscalls and files missing in CurlSandbox to a new PolicyBuilder
auto policy_builder = std::make_unique<sandbox2::PolicyBuilder>();
(*policy_builder)
.AllowFutexOp(FUTEX_WAIT_PRIVATE)
.AllowGetPIDs()
.AllowGetRandom()
.AllowHandleSignals()
.AllowSyscall(__NR_sysinfo)
.AddFile(ssl_certificate)
.AddFile(ssl_key)
.AddFile(ca_certificates);
// Provide the new PolicyBuilder to ModifyPolicy in CurlSandbox
return curl::CurlSapiSandbox::ModifyPolicy(policy_builder.get());
}
std::string ssl_certificate;
std::string ssl_key;
std::string ca_certificates;
};
absl::Status Example3(std::string ssl_certificate, std::string ssl_key,
std::string ssl_key_password,
std::string ca_certificates) {
// Initialize sandbox2 and sapi
CurlSapiSandboxEx3 sandbox(ssl_certificate, ssl_key, ca_certificates);
SAPI_RETURN_IF_ERROR(sandbox.Init());
curl::CurlApi api(&sandbox);
int curl_code;
// Initialize curl (CURL_GLOBAL_DEFAULT = 3)
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_global_init(3l));
if (curl_code != 0) {
return absl::UnavailableError(
absl::StrCat("curl_global_init failed: ", curl_code));
}
// Initialize curl easy handle
curl::CURL* curl_handle;
SAPI_ASSIGN_OR_RETURN(curl_handle, api.curl_easy_init());
sapi::v::RemotePtr curl(curl_handle);
if (!curl_handle) {
return absl::UnavailableError("curl_easy_init failed: curl is NULL");
}
// Specify URL to get (using HTTPS)
sapi::v::ConstCStr url("https://example.com");
SAPI_ASSIGN_OR_RETURN(
curl_code,
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_URL, url.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set the SSL certificate type to "PEM"
sapi::v::ConstCStr ssl_cert_type("PEM");
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERTTYPE,
ssl_cert_type.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set the certificate for client authentication
sapi::v::ConstCStr sapi_ssl_certificate(ssl_certificate.c_str());
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLCERT,
sapi_ssl_certificate.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set the private key for client authentication
sapi::v::ConstCStr sapi_ssl_key(ssl_key.c_str());
SAPI_ASSIGN_OR_RETURN(curl_code,
api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_SSLKEY,
sapi_ssl_key.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set the password used to protect the private key
sapi::v::ConstCStr sapi_ssl_key_password(ssl_key_password.c_str());
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_KEYPASSWD,
sapi_ssl_key_password.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Set the file with the certificates vaildating the server
sapi::v::ConstCStr sapi_ca_certificates(ca_certificates.c_str());
SAPI_ASSIGN_OR_RETURN(
curl_code, api.curl_easy_setopt_ptr(&curl, curl::CURLOPT_CAINFO,
sapi_ca_certificates.PtrBefore()));
if (curl_code != 0) {
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_ptr failed: ", curl_code));
}
// Verify the authenticity of the server
SAPI_ASSIGN_OR_RETURN(
curl_code,
api.curl_easy_setopt_long(&curl, curl::CURLOPT_SSL_VERIFYPEER, 1L));
if (curl_code != 0) {
return absl::UnavailableError(
absl::StrCat("curl_easy_setopt_long failed: ", curl_code));
}
// Perform the request
SAPI_ASSIGN_OR_RETURN(curl_code, api.curl_easy_perform(&curl));
if (curl_code != 0) {
return absl::UnavailableError(
absl::StrCat("curl_easy_perform failed: ", curl_code));
}
// Cleanup curl easy handle
SAPI_RETURN_IF_ERROR(api.curl_easy_cleanup(&curl));
// Cleanup curl
SAPI_RETURN_IF_ERROR(api.curl_global_cleanup());
return absl::OkStatus();
}
} // namespace
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
// Get input parameters (should be absolute paths)
if (argc != 5) {
LOG(ERROR) << "wrong number of arguments (4 expected)";
return EXIT_FAILURE;
}
if (absl::Status status = Example3(argv[1], argv[2], argv[3], argv[4]);
!status.ok()) {
LOG(ERROR) << "Example3 failed: " << status.ToString();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}