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