• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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