1*ec63e07aSXin Li // Copyright 2022 Google LLC
2*ec63e07aSXin Li //
3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License");
4*ec63e07aSXin Li // you may not use this file except in compliance with the License.
5*ec63e07aSXin Li // You may obtain a copy of the License at
6*ec63e07aSXin Li //
7*ec63e07aSXin Li // https://www.apache.org/licenses/LICENSE-2.0
8*ec63e07aSXin Li //
9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software
10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS,
11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*ec63e07aSXin Li // See the License for the specific language governing permissions and
13*ec63e07aSXin Li // limitations under the License.
14*ec63e07aSXin Li
15*ec63e07aSXin Li #include "libidn2_sapi.h" // NOLINT(build/include)
16*ec63e07aSXin Li
17*ec63e07aSXin Li #include <cstdlib>
18*ec63e07aSXin Li #include <fstream>
19*ec63e07aSXin Li #include <iostream>
20*ec63e07aSXin Li
21*ec63e07aSXin Li #include "absl/log/log.h"
22*ec63e07aSXin Li #include "sandboxed_api/util/fileops.h"
23*ec63e07aSXin Li
24*ec63e07aSXin Li static constexpr std::size_t kMaxDomainNameLength = 256;
25*ec63e07aSXin Li static constexpr int kMinPossibleKnownError = -10000;
26*ec63e07aSXin Li
ProcessErrors(const absl::StatusOr<int> & untrusted_res,sapi::v::GenericPtr & ptr)27*ec63e07aSXin Li absl::StatusOr<std::string> IDN2Lib::ProcessErrors(
28*ec63e07aSXin Li const absl::StatusOr<int>& untrusted_res, sapi::v::GenericPtr& ptr) {
29*ec63e07aSXin Li SAPI_RETURN_IF_ERROR(untrusted_res.status());
30*ec63e07aSXin Li int res = untrusted_res.value();
31*ec63e07aSXin Li if (res < 0) {
32*ec63e07aSXin Li if (res == IDN2_MALLOC) {
33*ec63e07aSXin Li return absl::ResourceExhaustedError("malloc() failed in libidn2");
34*ec63e07aSXin Li }
35*ec63e07aSXin Li if (res > kMinPossibleKnownError) {
36*ec63e07aSXin Li return absl::InvalidArgumentError(idn2_strerror(res));
37*ec63e07aSXin Li }
38*ec63e07aSXin Li return absl::InvalidArgumentError("Unexpected error");
39*ec63e07aSXin Li }
40*ec63e07aSXin Li sapi::v::RemotePtr p(reinterpret_cast<void*>(ptr.GetValue()));
41*ec63e07aSXin Li auto maybe_untrusted_name = sandbox_->GetCString(p, kMaxDomainNameLength);
42*ec63e07aSXin Li SAPI_RETURN_IF_ERROR(sandbox_->Free(&p));
43*ec63e07aSXin Li if (!maybe_untrusted_name.ok()) {
44*ec63e07aSXin Li return maybe_untrusted_name.status();
45*ec63e07aSXin Li }
46*ec63e07aSXin Li // FIXME: sanitize the result by checking that the return value is
47*ec63e07aSXin Li // valid ASCII (for a-labels) or UTF-8 (for u-labels) and doesn't
48*ec63e07aSXin Li // contain potentially malicious characters.
49*ec63e07aSXin Li return *maybe_untrusted_name;
50*ec63e07aSXin Li }
51*ec63e07aSXin Li
idn2_register_u8(const char * ulabel,const char * alabel)52*ec63e07aSXin Li absl::StatusOr<std::string> IDN2Lib::idn2_register_u8(const char* ulabel,
53*ec63e07aSXin Li const char* alabel) {
54*ec63e07aSXin Li std::optional<sapi::v::ConstCStr> alabel_ptr;
55*ec63e07aSXin Li std::optional<sapi::v::ConstCStr> ulabel_ptr;
56*ec63e07aSXin Li if (ulabel) {
57*ec63e07aSXin Li ulabel_ptr.emplace(ulabel);
58*ec63e07aSXin Li }
59*ec63e07aSXin Li if (alabel) {
60*ec63e07aSXin Li alabel_ptr.emplace(alabel);
61*ec63e07aSXin Li }
62*ec63e07aSXin Li sapi::v::GenericPtr ptr;
63*ec63e07aSXin Li sapi::v::NullPtr null_ptr;
64*ec63e07aSXin Li const auto untrusted_res = api_.idn2_register_u8(
65*ec63e07aSXin Li ulabel ? ulabel_ptr->PtrBefore() : &null_ptr,
66*ec63e07aSXin Li alabel ? alabel_ptr->PtrBefore() : &null_ptr, ptr.PtrAfter(),
67*ec63e07aSXin Li IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
68*ec63e07aSXin Li return this->ProcessErrors(untrusted_res, ptr);
69*ec63e07aSXin Li }
70*ec63e07aSXin Li
SapiGeneric(const char * data,absl::StatusOr<int> (IDN2Api::* cb)(sapi::v::Ptr * input,sapi::v::Ptr * output,int flags))71*ec63e07aSXin Li absl::StatusOr<std::string> IDN2Lib::SapiGeneric(
72*ec63e07aSXin Li const char* data,
73*ec63e07aSXin Li absl::StatusOr<int> (IDN2Api::*cb)(sapi::v::Ptr* input,
74*ec63e07aSXin Li sapi::v::Ptr* output, int flags)) {
75*ec63e07aSXin Li sapi::v::ConstCStr src(data);
76*ec63e07aSXin Li sapi::v::GenericPtr ptr;
77*ec63e07aSXin Li
78*ec63e07aSXin Li absl::StatusOr<int> untrusted_res = ((api_).*(cb))(
79*ec63e07aSXin Li src.PtrBefore(), ptr.PtrAfter(), IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
80*ec63e07aSXin Li return this->ProcessErrors(untrusted_res, ptr);
81*ec63e07aSXin Li }
82*ec63e07aSXin Li
idn2_to_unicode_8z8z(const char * data)83*ec63e07aSXin Li absl::StatusOr<std::string> IDN2Lib::idn2_to_unicode_8z8z(const char* data) {
84*ec63e07aSXin Li return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_to_unicode_8z8z);
85*ec63e07aSXin Li }
86*ec63e07aSXin Li
idn2_to_ascii_8z(const char * data)87*ec63e07aSXin Li absl::StatusOr<std::string> IDN2Lib::idn2_to_ascii_8z(const char* data) {
88*ec63e07aSXin Li return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_to_ascii_8z);
89*ec63e07aSXin Li }
90*ec63e07aSXin Li
idn2_lookup_u8(const char * data)91*ec63e07aSXin Li absl::StatusOr<std::string> IDN2Lib::idn2_lookup_u8(const char* data) {
92*ec63e07aSXin Li return IDN2Lib::SapiGeneric(data, &IDN2Api::idn2_lookup_u8);
93*ec63e07aSXin Li }
94