1 /*
2 * Copyright (C) 2016 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 "wifi_system/hostapd_manager.h"
18
19 #include <iomanip>
20 #include <sstream>
21 #include <string>
22 #include <vector>
23
24 #include <android-base/file.h>
25 #include <android-base/logging.h>
26 #include <android-base/parseint.h>
27 #include <android-base/stringprintf.h>
28 #include <cutils/properties.h>
29 #include <openssl/evp.h>
30 #include <openssl/sha.h>
31 #include <private/android_filesystem_config.h>
32
33 #include "wifi_system/supplicant_manager.h"
34
35 using android::base::ParseInt;
36 using android::base::ReadFileToString;
37 using android::base::StringPrintf;
38 using android::base::WriteStringToFile;
39 using std::string;
40 using std::vector;
41 using std::stringstream;
42
43 namespace android {
44 namespace wifi_system {
45 namespace {
46
47 const int kDefaultApChannel = 6;
48 const char kHostapdServiceName[] = "hostapd";
49 const char kHostapdConfigFilePath[] = "/data/misc/wifi/hostapd.conf";
50
51
GeneratePsk(const vector<uint8_t> & ssid,const vector<uint8_t> & passphrase)52 string GeneratePsk(const vector<uint8_t>& ssid,
53 const vector<uint8_t>& passphrase) {
54 string result;
55 unsigned char psk[SHA256_DIGEST_LENGTH];
56
57 // Use the PKCS#5 PBKDF2 with 4096 iterations
58 if (PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(passphrase.data()),
59 passphrase.size(),
60 ssid.data(), ssid.size(),
61 4096, sizeof(psk), psk) != 1) {
62 LOG(ERROR) << "Cannot generate PSK using PKCS#5 PBKDF2";
63 return result;
64 }
65
66 stringstream ss;
67 ss << std::hex;
68 ss << std::setfill('0');
69 for (int j = 0; j < SHA256_DIGEST_LENGTH; j++) {
70 ss << std::setw(2) << static_cast<unsigned int>(psk[j]);
71 }
72 result = ss.str();
73
74 return result;
75 }
76
77 } // namespace
78
StartHostapd()79 bool HostapdManager::StartHostapd() {
80 if (!SupplicantManager::EnsureEntropyFileExists()) {
81 LOG(WARNING) << "Wi-Fi entropy file was not created";
82 }
83
84 if (property_set("ctl.start", kHostapdServiceName) != 0) {
85 LOG(ERROR) << "Failed to start SoftAP";
86 return false;
87 }
88
89 LOG(DEBUG) << "SoftAP started successfully";
90 return true;
91 }
92
StopHostapd()93 bool HostapdManager::StopHostapd() {
94 LOG(DEBUG) << "Stopping the SoftAP service...";
95
96 if (property_set("ctl.stop", kHostapdServiceName) < 0) {
97 LOG(ERROR) << "Failed to stop hostapd service!";
98 return false;
99 }
100
101 LOG(DEBUG) << "SoftAP stopped successfully";
102 return true;
103 }
104
WriteHostapdConfig(const string & config)105 bool HostapdManager::WriteHostapdConfig(const string& config) {
106 if (!WriteStringToFile(config, kHostapdConfigFilePath,
107 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
108 AID_WIFI, AID_WIFI)) {
109 int error = errno;
110 LOG(ERROR) << "Cannot write hostapd config to \""
111 << kHostapdConfigFilePath << "\": " << strerror(error);
112 struct stat st;
113 int result = stat(kHostapdConfigFilePath, &st);
114 if (result == 0) {
115 LOG(ERROR) << "hostapd config file uid: "<< st.st_uid << ", gid: " << st.st_gid
116 << ", mode: " << st.st_mode;
117 } else {
118 LOG(ERROR) << "Error calling stat() on hostapd config file: " << strerror(errno);
119 }
120 return false;
121 }
122 return true;
123 }
124
CreateHostapdConfig(const string & interface_name,const vector<uint8_t> ssid,bool is_hidden,int channel,EncryptionType encryption_type,const vector<uint8_t> passphrase)125 string HostapdManager::CreateHostapdConfig(
126 const string& interface_name,
127 const vector<uint8_t> ssid,
128 bool is_hidden,
129 int channel,
130 EncryptionType encryption_type,
131 const vector<uint8_t> passphrase) {
132 string result;
133
134 if (channel < 0) {
135 channel = kDefaultApChannel;
136 }
137
138 if (ssid.size() > 32) {
139 LOG(ERROR) << "SSIDs must be <= 32 bytes long";
140 return result;
141 }
142
143 stringstream ss;
144 ss << std::hex;
145 ss << std::setfill('0');
146 for (uint8_t b : ssid) {
147 ss << std::setw(2) << static_cast<unsigned int>(b);
148 }
149 const string ssid_as_string = ss.str();
150
151 string encryption_config;
152 if (encryption_type != EncryptionType::kOpen) {
153 string psk = GeneratePsk(ssid, passphrase);
154 if (psk.empty()) {
155 return result;
156 }
157 if (encryption_type == EncryptionType::kWpa) {
158 encryption_config = StringPrintf("wpa=3\n"
159 "wpa_pairwise=TKIP CCMP\n"
160 "wpa_psk=%s\n", psk.c_str());
161 } else if (encryption_type == EncryptionType::kWpa2) {
162 encryption_config = StringPrintf("wpa=2\n"
163 "rsn_pairwise=CCMP\n"
164 "wpa_psk=%s\n", psk.c_str());
165 } else {
166 using encryption_t = std::underlying_type<EncryptionType>::type;
167 LOG(ERROR) << "Unknown encryption type ("
168 << static_cast<encryption_t>(encryption_type)
169 << ")";
170 return result;
171 }
172 }
173
174 result = StringPrintf(
175 "interface=%s\n"
176 "driver=nl80211\n"
177 "ctrl_interface=/data/misc/wifi/hostapd/ctrl\n"
178 // ssid2 signals to hostapd that the value is not a literal value
179 // for use as a SSID. In this case, we're giving it a hex string
180 // and hostapd needs to expect that.
181 "ssid2=%s\n"
182 "channel=%d\n"
183 "ieee80211n=1\n"
184 "hw_mode=%c\n"
185 "ignore_broadcast_ssid=%d\n"
186 "wowlan_triggers=any\n"
187 "%s",
188 interface_name.c_str(),
189 ssid_as_string.c_str(),
190 channel,
191 (channel <= 14) ? 'g' : 'a',
192 (is_hidden) ? 1 : 0,
193 encryption_config.c_str());
194 return result;
195 }
196
197 } // namespace wifi_system
198 } // namespace android
199