1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "adb_wifi.h" 18 19 #include <fstream> 20 #include <random> 21 #include <thread> 22 23 #include <adb/crypto/key.h> 24 #include <adb/crypto/x509_generator.h> 25 #include <android-base/file.h> 26 #include <android-base/parsenetaddress.h> 27 #include "client/pairing/pairing_client.h" 28 29 #include "adb_auth.h" 30 #include "adb_known_hosts.pb.h" 31 #include "adb_mdns.h" 32 #include "adb_utils.h" 33 #include "client/adb_client.h" 34 #include "sysdeps.h" 35 36 using adbwifi::pairing::PairingClient; 37 using namespace adb::crypto; 38 39 struct PairingResultWaiter { 40 std::mutex mutex_; 41 std::condition_variable cv_; 42 std::optional<bool> is_valid_; 43 PeerInfo peer_info_; 44 45 static void OnResult(const PeerInfo* peer_info, void* opaque) { 46 CHECK(opaque); 47 auto* p = reinterpret_cast<PairingResultWaiter*>(opaque); 48 { 49 std::lock_guard<std::mutex> lock(p->mutex_); 50 if (peer_info) { 51 memcpy(&(p->peer_info_), peer_info, sizeof(PeerInfo)); 52 } 53 p->is_valid_ = (peer_info != nullptr); 54 } 55 p->cv_.notify_one(); 56 } 57 }; // PairingResultWaiter 58 59 void adb_wifi_init() {} 60 61 static std::vector<uint8_t> stringToUint8(const std::string& str) { 62 auto* p8 = reinterpret_cast<const uint8_t*>(str.data()); 63 return std::vector<uint8_t>(p8, p8 + str.length()); 64 } 65 66 // Tries to replace the |old_file| with |new_file|. 67 // On success, then |old_file| has been removed and replaced with the 68 // contents of |new_file|, |new_file| will be removed, and only |old_file| will 69 // remain. 70 // On failure, both files will be unchanged. 71 // |new_file| must exist, but |old_file| does not need to exist. 72 bool SafeReplaceFile(std::string_view old_file, std::string_view new_file) { 73 std::string to_be_deleted(old_file); 74 to_be_deleted += ".tbd"; 75 76 bool old_renamed = true; 77 if (adb_rename(old_file.data(), to_be_deleted.c_str()) != 0) { 78 // Don't exit here. This is not necessarily an error, because |old_file| 79 // may not exist. 80 PLOG(INFO) << "Failed to rename " << old_file; 81 old_renamed = false; 82 } 83 84 if (adb_rename(new_file.data(), old_file.data()) != 0) { 85 PLOG(ERROR) << "Unable to rename file (" << new_file << " => " << old_file << ")"; 86 if (old_renamed) { 87 // Rename the .tbd file back to it's original name 88 adb_rename(to_be_deleted.c_str(), old_file.data()); 89 } 90 return false; 91 } 92 93 adb_unlink(to_be_deleted.c_str()); 94 return true; 95 } 96 97 static std::string get_user_known_hosts_path() { 98 return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adb_known_hosts.pb"; 99 } 100 101 bool load_known_hosts_from_file(const std::string& path, adb::proto::AdbKnownHosts& known_hosts) { 102 // Check for file existence. 103 struct stat buf; 104 if (stat(path.c_str(), &buf) == -1) { 105 LOG(INFO) << "Known hosts file [" << path << "] does not exist..."; 106 return false; 107 } 108 109 std::ifstream file(path, std::ios::binary); 110 if (!file) { 111 PLOG(ERROR) << "Unable to open [" << path << "]."; 112 return false; 113 } 114 115 if (!known_hosts.ParseFromIstream(&file)) { 116 PLOG(ERROR) << "Failed to parse [" << path << "]. Deleting it as it may be corrupted."; 117 adb_unlink(path.c_str()); 118 return false; 119 } 120 121 return true; 122 } 123 124 static bool write_known_host_to_file(std::string& known_host) { 125 std::string path = get_user_known_hosts_path(); 126 if (path.empty()) { 127 PLOG(ERROR) << "Error getting user known hosts filename"; 128 return false; 129 } 130 131 adb::proto::AdbKnownHosts known_hosts; 132 load_known_hosts_from_file(path, known_hosts); 133 auto* host_info = known_hosts.add_host_infos(); 134 host_info->set_guid(known_host); 135 136 std::unique_ptr<TemporaryFile> temp_file(new TemporaryFile(adb_get_android_dir_path())); 137 if (temp_file->fd == -1) { 138 PLOG(ERROR) << "Failed to open [" << temp_file->path << "] for writing"; 139 return false; 140 } 141 142 if (!known_hosts.SerializeToFileDescriptor(temp_file->fd)) { 143 LOG(ERROR) << "Unable to write out adb_knowns_hosts"; 144 return false; 145 } 146 temp_file->DoNotRemove(); 147 std::string temp_file_name(temp_file->path); 148 temp_file.reset(); 149 150 // Replace the existing adb_known_hosts with the new one 151 if (!SafeReplaceFile(path, temp_file_name.c_str())) { 152 LOG(ERROR) << "Failed to replace old adb_known_hosts"; 153 adb_unlink(temp_file_name.c_str()); 154 return false; 155 } 156 chmod(path.c_str(), S_IRUSR | S_IWUSR | S_IRGRP); 157 158 return true; 159 } 160 161 bool adb_wifi_is_known_host(const std::string& host) { 162 std::string path = get_user_known_hosts_path(); 163 if (path.empty()) { 164 PLOG(ERROR) << "Error getting user known hosts filename"; 165 return false; 166 } 167 168 adb::proto::AdbKnownHosts known_hosts; 169 if (!load_known_hosts_from_file(path, known_hosts)) { 170 return false; 171 } 172 173 for (const auto& host_info : known_hosts.host_infos()) { 174 if (host == host_info.guid()) { 175 return true; 176 } 177 } 178 return false; 179 } 180 181 void adb_wifi_pair_device(const std::string& host, const std::string& password, 182 std::string& response) { 183 auto mdns_info = mdns_get_pairing_service_info(host); 184 185 if (!mdns_info.has_value()) { 186 // Check the address for a valid address and port. 187 std::string parsed_host; 188 std::string err; 189 int port = -1; 190 if (!android::base::ParseNetAddress(host, &parsed_host, &port, nullptr, &err)) { 191 response = "Failed to parse address for pairing: " + err; 192 return; 193 } 194 if (port <= 0 || port > 65535) { 195 response = "Invalid port while parsing address [" + host + "]"; 196 return; 197 } 198 } 199 200 auto priv_key = adb_auth_get_user_privkey(); 201 auto x509_cert = GenerateX509Certificate(priv_key.get()); 202 if (!x509_cert) { 203 LOG(ERROR) << "Unable to create X509 certificate for pairing"; 204 return; 205 } 206 auto cert_str = X509ToPEMString(x509_cert.get()); 207 auto priv_str = Key::ToPEMString(priv_key.get()); 208 209 // Send our public key on pairing success 210 PeerInfo system_info = {}; 211 system_info.type = ADB_RSA_PUB_KEY; 212 std::string public_key = adb_auth_get_userkey(); 213 CHECK_LE(public_key.size(), sizeof(system_info.data) - 1); // -1 for null byte 214 memcpy(system_info.data, public_key.data(), public_key.size()); 215 216 auto pswd8 = stringToUint8(password); 217 auto cert8 = stringToUint8(cert_str); 218 auto priv8 = stringToUint8(priv_str); 219 220 auto client = PairingClient::Create(pswd8, system_info, cert8, priv8); 221 if (client == nullptr) { 222 response = "Failed: unable to create pairing client."; 223 return; 224 } 225 226 PairingResultWaiter waiter; 227 std::unique_lock<std::mutex> lock(waiter.mutex_); 228 if (!client->Start(mdns_info.has_value() 229 ? android::base::StringPrintf("%s:%d", mdns_info->addr.c_str(), 230 mdns_info->port) 231 : host, 232 waiter.OnResult, &waiter)) { 233 response = "Failed: Unable to start pairing client."; 234 return; 235 } 236 waiter.cv_.wait(lock, [&]() { return waiter.is_valid_.has_value(); }); 237 if (!*(waiter.is_valid_)) { 238 response = "Failed: Wrong password or connection was dropped."; 239 return; 240 } 241 242 if (waiter.peer_info_.type != ADB_DEVICE_GUID) { 243 response = "Failed: Successfully paired but server returned unknown response="; 244 response += waiter.peer_info_.type; 245 return; 246 } 247 248 std::string device_guid = reinterpret_cast<const char*>(waiter.peer_info_.data); 249 response = "Successfully paired to " + host + " [guid=" + device_guid + "]"; 250 251 // Write to adb_known_hosts 252 write_known_host_to_file(device_guid); 253 // Try to auto-connect. 254 adb_secure_connect_by_service_name(device_guid); 255 } 256