1944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley/* 2944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * Copyright (C) 2016 The Android Open Source Project 3944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * 4944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * Licensed under the Apache License, Version 2.0 (the "License"); 5944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * you may not use this file except in compliance with the License. 6944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * You may obtain a copy of the License at 7944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * 8944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * http://www.apache.org/licenses/LICENSE-2.0 9944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * 10944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * Unless required by applicable law or agreed to in writing, software 11944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * distributed under the License is distributed on an "AS IS" BASIS, 12944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * See the License for the specific language governing permissions and 14944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley * limitations under the License. 15944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley */ 16944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 17944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include "wifi_system/hostapd_manager.h" 18944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 19944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include <iomanip> 20944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include <sstream> 21944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include <string> 22944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include <vector> 23944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 24944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include <android-base/file.h> 25944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include <android-base/logging.h> 26aa31194b9c1f41fbbba294332ba0462b3d686bc6Christopher Wiley#include <android-base/parseint.h> 27944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include <android-base/stringprintf.h> 28944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include <cutils/properties.h> 29944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include <openssl/evp.h> 30944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include <openssl/sha.h> 31944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley#include <private/android_filesystem_config.h> 32944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 33ff66f41f8f457bf5e9c0c75d72dbe74f9dfc3102Ningyuan Wang#include "wifi_system/supplicant_manager.h" 34944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 35aa31194b9c1f41fbbba294332ba0462b3d686bc6Christopher Wileyusing android::base::ParseInt; 36aa31194b9c1f41fbbba294332ba0462b3d686bc6Christopher Wileyusing android::base::ReadFileToString; 37944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileyusing android::base::StringPrintf; 38944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileyusing android::base::WriteStringToFile; 39944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileyusing std::string; 40944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileyusing std::vector; 41944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileyusing std::stringstream; 42944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 43944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileynamespace android { 44944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileynamespace wifi_system { 45944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileynamespace { 46944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 47944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileyconst int kDefaultApChannel = 6; 48944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileyconst char kHostapdServiceName[] = "hostapd"; 49944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileyconst char kHostapdConfigFilePath[] = "/data/misc/wifi/hostapd.conf"; 50aa31194b9c1f41fbbba294332ba0462b3d686bc6Christopher Wiley 51944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 52944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileystring GeneratePsk(const vector<uint8_t>& ssid, 53944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley const vector<uint8_t>& passphrase) { 54944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley string result; 55944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley unsigned char psk[SHA256_DIGEST_LENGTH]; 56944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 57944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley // Use the PKCS#5 PBKDF2 with 4096 iterations 58944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley if (PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(passphrase.data()), 59944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley passphrase.size(), 60944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley ssid.data(), ssid.size(), 61944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 4096, sizeof(psk), psk) != 1) { 62944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley LOG(ERROR) << "Cannot generate PSK using PKCS#5 PBKDF2"; 63944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return result; 64944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 65944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 66944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley stringstream ss; 67944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley ss << std::hex; 68944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley ss << std::setfill('0'); 69944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley for (int j = 0; j < SHA256_DIGEST_LENGTH; j++) { 70944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley ss << std::setw(2) << static_cast<unsigned int>(psk[j]); 71944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 72944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley result = ss.str(); 73944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 74944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return result; 75944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley} 76944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 77944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley} // namespace 78944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 79944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileybool HostapdManager::StartHostapd() { 80ff66f41f8f457bf5e9c0c75d72dbe74f9dfc3102Ningyuan Wang if (!SupplicantManager::EnsureEntropyFileExists()) { 81944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley LOG(WARNING) << "Wi-Fi entropy file was not created"; 82944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 83944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 84944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley if (property_set("ctl.start", kHostapdServiceName) != 0) { 85944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley LOG(ERROR) << "Failed to start SoftAP"; 86944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return false; 87944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 88944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 89944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley LOG(DEBUG) << "SoftAP started successfully"; 90944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return true; 91944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley} 92944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 93aa31194b9c1f41fbbba294332ba0462b3d686bc6Christopher Wileybool HostapdManager::StopHostapd() { 94944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley LOG(DEBUG) << "Stopping the SoftAP service..."; 95944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 96944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley if (property_set("ctl.stop", kHostapdServiceName) < 0) { 97944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley LOG(ERROR) << "Failed to stop hostapd service!"; 98944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return false; 99944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 100944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 101944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley LOG(DEBUG) << "SoftAP stopped successfully"; 102944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return true; 103944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley} 104944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 105944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileybool HostapdManager::WriteHostapdConfig(const string& config) { 106944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley if (!WriteStringToFile(config, kHostapdConfigFilePath, 107944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 1081d3a41b9b46eb573058fdd7422d4ebc5b4f1108fChristopher Wiley AID_WIFI, AID_WIFI)) { 109944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley int error = errno; 110944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley LOG(ERROR) << "Cannot write hostapd config to \"" 111944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley << kHostapdConfigFilePath << "\": " << strerror(error); 11236eb645cfec7dfe8c400b85ca12172060af061cfNingyuan Wang struct stat st; 11336eb645cfec7dfe8c400b85ca12172060af061cfNingyuan Wang int result = stat(kHostapdConfigFilePath, &st); 11436eb645cfec7dfe8c400b85ca12172060af061cfNingyuan Wang if (result == 0) { 11536eb645cfec7dfe8c400b85ca12172060af061cfNingyuan Wang LOG(ERROR) << "hostapd config file uid: "<< st.st_uid << ", gid: " << st.st_gid 11636eb645cfec7dfe8c400b85ca12172060af061cfNingyuan Wang << ", mode: " << st.st_mode; 11736eb645cfec7dfe8c400b85ca12172060af061cfNingyuan Wang } else { 11836eb645cfec7dfe8c400b85ca12172060af061cfNingyuan Wang LOG(ERROR) << "Error calling stat() on hostapd config file: " << strerror(errno); 11936eb645cfec7dfe8c400b85ca12172060af061cfNingyuan Wang } 120944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return false; 121944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 122944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return true; 123944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley} 124944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 125944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wileystring HostapdManager::CreateHostapdConfig( 126944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley const string& interface_name, 127944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley const vector<uint8_t> ssid, 128944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley bool is_hidden, 129944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley int channel, 130944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley EncryptionType encryption_type, 131944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley const vector<uint8_t> passphrase) { 132944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley string result; 133944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 134944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley if (channel < 0) { 135944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley channel = kDefaultApChannel; 136944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 137944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 138944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley if (ssid.size() > 32) { 139944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley LOG(ERROR) << "SSIDs must be <= 32 bytes long"; 140944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return result; 141944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 142944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 143944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley stringstream ss; 144944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley ss << std::hex; 145944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley ss << std::setfill('0'); 146944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley for (uint8_t b : ssid) { 147944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley ss << std::setw(2) << static_cast<unsigned int>(b); 148944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 149944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley const string ssid_as_string = ss.str(); 150944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 151944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley string encryption_config; 152944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley if (encryption_type != EncryptionType::kOpen) { 153944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley string psk = GeneratePsk(ssid, passphrase); 154944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley if (psk.empty()) { 155944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return result; 156944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 157944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley if (encryption_type == EncryptionType::kWpa) { 158944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley encryption_config = StringPrintf("wpa=3\n" 159944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "wpa_pairwise=TKIP CCMP\n" 160944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "wpa_psk=%s\n", psk.c_str()); 161944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } else if (encryption_type == EncryptionType::kWpa2) { 162944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley encryption_config = StringPrintf("wpa=2\n" 163944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "rsn_pairwise=CCMP\n" 164944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "wpa_psk=%s\n", psk.c_str()); 165944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } else { 166944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley using encryption_t = std::underlying_type<EncryptionType>::type; 167944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley LOG(ERROR) << "Unknown encryption type (" 168944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley << static_cast<encryption_t>(encryption_type) 169944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley << ")"; 170944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return result; 171944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 172944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley } 173944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 174944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley result = StringPrintf( 175944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "interface=%s\n" 176944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "driver=nl80211\n" 17779c7200789531ad044999a0de7ba9557c8f4c293Christopher Wiley "ctrl_interface=/data/misc/wifi/hostapd/ctrl\n" 178944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley // ssid2 signals to hostapd that the value is not a literal value 179944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley // for use as a SSID. In this case, we're giving it a hex string 180944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley // and hostapd needs to expect that. 181944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "ssid2=%s\n" 182944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "channel=%d\n" 183944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "ieee80211n=1\n" 184944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "hw_mode=%c\n" 185944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "ignore_broadcast_ssid=%d\n" 186944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "wowlan_triggers=any\n" 187944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley "%s", 188944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley interface_name.c_str(), 189944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley ssid_as_string.c_str(), 190944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley channel, 191944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley (channel <= 14) ? 'g' : 'a', 192944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley (is_hidden) ? 1 : 0, 193944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley encryption_config.c_str()); 194944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley return result; 195944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley} 196944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley 197944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley} // namespace wifi_system 198944db7cbdafa91279b40dd8a7737307e49cf711eChristopher Wiley} // namespace android 199