Java tutorial
/******************************************************************************* * Copyright (c) 2011, 2016 Eurotech and/or its affiliates * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.net.admin.visitor.linux; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.List; import org.apache.commons.io.FileUtils; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.core.net.NetworkConfiguration; import org.eclipse.kura.core.net.NetworkConfigurationVisitor; import org.eclipse.kura.core.net.WifiInterfaceAddressConfigImpl; import org.eclipse.kura.core.util.IOUtil; import org.eclipse.kura.core.util.ProcessUtil; import org.eclipse.kura.core.util.SafeProcess; import org.eclipse.kura.linux.net.util.KuraConstants; import org.eclipse.kura.linux.net.wifi.WpaSupplicantManager; import org.eclipse.kura.net.NetConfig; import org.eclipse.kura.net.NetConfigIP4; import org.eclipse.kura.net.NetInterfaceAddressConfig; import org.eclipse.kura.net.NetInterfaceConfig; import org.eclipse.kura.net.NetInterfaceStatus; import org.eclipse.kura.net.NetInterfaceType; import org.eclipse.kura.net.admin.visitor.linux.util.KuranetConfig; import org.eclipse.kura.net.admin.visitor.linux.util.WpaSupplicantUtil; import org.eclipse.kura.net.wifi.WifiCiphers; import org.eclipse.kura.net.wifi.WifiConfig; import org.eclipse.kura.net.wifi.WifiMode; import org.eclipse.kura.net.wifi.WifiSecurity; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class WpaSupplicantConfigWriter implements NetworkConfigurationVisitor { private static final Logger s_logger = LoggerFactory.getLogger(WpaSupplicantConfigWriter.class); private static final String WPA_TMP_CONFIG_FILE = "/etc/wpa_supplicant.conf.tmp"; private static final String TMP_WPA_CONFIG_FILE = "/tmp/wpa_supplicant.conf"; private static final String OS_VERSION = System.getProperty("kura.os.version"); private static final String HEXES = "0123456789ABCDEF"; private static WpaSupplicantConfigWriter s_instance; public static WpaSupplicantConfigWriter getInstance() { if (s_instance == null) { s_instance = new WpaSupplicantConfigWriter(); } return s_instance; } @Override public void visit(NetworkConfiguration config) throws KuraException { List<NetInterfaceConfig<? extends NetInterfaceAddressConfig>> netInterfaceConfigs = config .getModifiedNetInterfaceConfigs(); for (NetInterfaceConfig<? extends NetInterfaceAddressConfig> netInterfaceConfig : netInterfaceConfigs) { if (netInterfaceConfig.getType() == NetInterfaceType.WIFI) { // ignore 'mon' interface if (netInterfaceConfig.getName().startsWith("mon.")) { continue; } writeConfig(netInterfaceConfig); } } } public void generateTempWpaSupplicantConf(WifiConfig wifiConfig, String interfaceName) throws KuraException { try { generateWpaSupplicantConf(wifiConfig, interfaceName, TMP_WPA_CONFIG_FILE); } catch (Exception e) { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } } public void generateTempWpaSupplicantConf() throws KuraException { try { String fileAsString = IOUtil.readResource(FrameworkUtil.getBundle(getClass()), "/src/main/resources/wifi/wpasupplicant.conf"); File outputFile = new File(TMP_WPA_CONFIG_FILE); copyFile(fileAsString, outputFile); } catch (Exception e) { throw KuraException.internalError("Failed to generate wpa_supplicant.conf"); } } private void writeConfig(NetInterfaceConfig<? extends NetInterfaceAddressConfig> netInterfaceConfig) throws KuraException { String interfaceName = netInterfaceConfig.getName(); s_logger.debug("Writing wpa_supplicant config for {}", interfaceName); List<? extends NetInterfaceAddressConfig> netInterfaceAddressConfigs = netInterfaceConfig .getNetInterfaceAddresses(); if (netInterfaceAddressConfigs.size() > 0) { for (NetInterfaceAddressConfig netInterfaceAddressConfig : netInterfaceAddressConfigs) { if (netInterfaceAddressConfig instanceof WifiInterfaceAddressConfigImpl) { List<NetConfig> netConfigs = netInterfaceAddressConfig.getConfigs(); NetInterfaceStatus netInterfaceStatus = NetInterfaceStatus.netIPv4StatusDisabled; WifiMode wifiMode = ((WifiInterfaceAddressConfigImpl) netInterfaceAddressConfig).getMode(); WifiConfig infraConfig = null; WifiConfig adhocConfig = null; WifiConfig wpaSupplicantConfig = null; // Get the wifi configs if (netConfigs != null) { for (NetConfig netConfig : netConfigs) { if (netConfig instanceof WifiConfig) { if (((WifiConfig) netConfig).getMode() == WifiMode.ADHOC) { adhocConfig = (WifiConfig) netConfig; } else if (((WifiConfig) netConfig).getMode() == WifiMode.INFRA) { infraConfig = (WifiConfig) netConfig; } } else if (netConfig instanceof NetConfigIP4) { netInterfaceStatus = ((NetConfigIP4) netConfig).getStatus(); } } } if (netInterfaceStatus == NetInterfaceStatus.netIPv4StatusDisabled) { s_logger.info("Network interface status for " + interfaceName + " is disabled - not overwriting wpaconfig file"); return; } // Choose which config to write if (wifiMode == WifiMode.INFRA) { if (infraConfig != null) { StringBuilder key = new StringBuilder().append("net.interface.").append(interfaceName) .append(".config.wifi.infra.pingAccessPoint"); try { KuranetConfig.setProperty(key.toString(), Boolean.toString(infraConfig.pingAccessPoint())); } catch (IOException e) { s_logger.warn("Error setting KuranetConfig property", e); } key = new StringBuilder().append("net.interface.").append(interfaceName) .append(".config.wifi.infra.ignoreSSID"); try { KuranetConfig.setProperty(key.toString(), Boolean.toString(infraConfig.ignoreSSID())); } catch (IOException e) { s_logger.warn("Error setting KuranetConfig property", e); } wpaSupplicantConfig = infraConfig; } else { s_logger.debug("Not updating wpa_supplicant config - wifi mode is " + wifiMode + " but the infra config is null"); } } else if (wifiMode == WifiMode.ADHOC) { if (adhocConfig != null) { wpaSupplicantConfig = adhocConfig; } else { s_logger.debug("Not updating wpa_supplicant config - wifi mode is " + wifiMode + " but the adhoc config is null"); } } else if (wifiMode == WifiMode.MASTER) { if (infraConfig != null && adhocConfig != null) { wpaSupplicantConfig = infraConfig; // Choose the infra config if both are present? } else if (infraConfig != null) { wpaSupplicantConfig = infraConfig; } else if (adhocConfig != null) { wpaSupplicantConfig = adhocConfig; } else { s_logger.debug("Not updating wpa_supplicant config - wifi mode is " + wifiMode + " and the infra and adhoc configs are null"); } } // Write the config try { if (wpaSupplicantConfig != null) { s_logger.debug("Writing wifiConfig: {}", wpaSupplicantConfig); generateWpaSupplicantConf(wpaSupplicantConfig, interfaceName, WPA_TMP_CONFIG_FILE); moveWpaSupplicantConf(interfaceName, WPA_TMP_CONFIG_FILE); } } catch (Exception e) { s_logger.error("Failed to configure WPA Supplicant"); throw KuraException.internalError(e); } } } } } /* * This method generates the wpa_supplicant configuration file */ private void generateWpaSupplicantConf(WifiConfig wifiConfig, String interfaceName, String configFile) throws Exception { s_logger.debug("Generating WPA Supplicant Config"); s_logger.debug("Store wifiMode driver: {}", wifiConfig.getDriver()); StringBuilder key = new StringBuilder("net.interface." + interfaceName + ".config.wifi." + wifiConfig.getMode().toString().toLowerCase() + ".driver"); try { KuranetConfig.setProperty(key.toString(), wifiConfig.getDriver()); } catch (Exception e) { s_logger.error("Failed to save kuranet config", e); throw KuraException.internalError(e); } if (wifiConfig.getSecurity() == WifiSecurity.SECURITY_WEP) { File outputFile = new File(configFile); String fileAsString = null; if (wifiConfig.getMode() == WifiMode.INFRA) { fileAsString = IOUtil.readResource(FrameworkUtil.getBundle(getClass()), "/src/main/resources/wifi/wpasupplicant.conf_wep"); } else if (wifiConfig.getMode() == WifiMode.ADHOC) { fileAsString = IOUtil.readResource(FrameworkUtil.getBundle(getClass()), "/src/main/resources/wifi/wpasupplicant.conf_adhoc_wep"); fileAsString = fileAsString.replaceFirst("KURA_FREQUENCY", Integer.toString(WpaSupplicantUtil.convChannelToFrequency(wifiConfig.getChannels()[0]))); } else { throw KuraException.internalError( "Failed to generate wpa_supplicant.conf -- Inavlid mode: " + wifiConfig.getMode()); } // Remove the 'wheel' group assignment for Yocto image on Raspberry_Pi if (OS_VERSION.equals(KuraConstants.Raspberry_Pi.getImageName())) { fileAsString = fileAsString.replaceFirst("ctrl_interface_group=wheel", "#ctrl_interface_group=wheel"); } // Replace the necessary components fileAsString = fileAsString.replaceFirst("KURA_MODE", Integer.toString(getSupplicantMode(wifiConfig.getMode()))); if (wifiConfig.getSSID() != null) { fileAsString = fileAsString.replaceFirst("KURA_ESSID", wifiConfig.getSSID()); } else { throw KuraException.internalError("the essid can not be null"); } String passKey = new String(wifiConfig.getPasskey().getPassword()); if (passKey != null) { if (passKey.length() == 10) { // check to make sure it is all hex try { Long.parseLong(passKey, 16); } catch (Exception e) { throw KuraException.internalError( "the WEP key (passwd) must be all HEX characters (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f"); } // since we're here - save the password fileAsString = fileAsString.replaceFirst("KURA_WEP_KEY", passKey); } else if (passKey.length() == 26) { String part1 = passKey.substring(0, 13); String part2 = passKey.substring(13); try { Long.parseLong(part1, 16); Long.parseLong(part2, 16); } catch (Exception e) { throw KuraException.internalError( "the WEP key (passwd) must be all HEX characters (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f"); } // since we're here - save the password fileAsString = fileAsString.replaceFirst("KURA_WEP_KEY", passKey); } else if (passKey.length() == 32) { String part1 = passKey.substring(0, 10); String part2 = passKey.substring(10, 20); String part3 = passKey.substring(20); try { Long.parseLong(part1, 16); Long.parseLong(part2, 16); Long.parseLong(part3, 16); } catch (Exception e) { throw KuraException.internalError( "the WEP key (passwd) must be all HEX characters (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f"); } // since we're here - save the password fileAsString = fileAsString.replaceFirst("KURA_WEP_KEY", passKey); } else if (passKey.length() == 5 || passKey.length() == 13 || passKey.length() == 16) { // 5, 13, or 16 ASCII characters passKey = toHex(passKey); // since we're here - save the password fileAsString = fileAsString.replaceFirst("KURA_WEP_KEY", passKey); } else { throw KuraException .internalError("the WEP key (passwd) must be 10, 26, or 32 HEX characters in length"); } } if (wifiConfig.getBgscan() != null) { fileAsString = fileAsString.replaceFirst("KURA_BGSCAN", wifiConfig.getBgscan().toString()); } else { fileAsString = fileAsString.replaceFirst("KURA_BGSCAN", ""); } fileAsString = fileAsString.replaceFirst("KURA_SCANFREQ", getScanFrequenciesMHz(wifiConfig.getChannels())); // everything is set and we haven't failed - write the file copyFile(fileAsString, outputFile); return; } else if (wifiConfig.getSecurity() == WifiSecurity.SECURITY_WPA || wifiConfig.getSecurity() == WifiSecurity.SECURITY_WPA2 || wifiConfig.getSecurity() == WifiSecurity.SECURITY_WPA_WPA2) { File outputFile = new File(configFile); String fileAsString = null; if (wifiConfig.getMode() == WifiMode.INFRA) { fileAsString = IOUtil.readResource(FrameworkUtil.getBundle(getClass()), "/src/main/resources/wifi/wpasupplicant.conf_wpa"); } else if (wifiConfig.getMode() == WifiMode.ADHOC) { fileAsString = IOUtil.readResource(FrameworkUtil.getBundle(getClass()), "/src/main/resources/wifi/wpasupplicant.conf_adhoc_wpa"); fileAsString = fileAsString.replaceFirst("KURA_FREQUENCY", Integer.toString(WpaSupplicantUtil.convChannelToFrequency(wifiConfig.getChannels()[0]))); fileAsString = fileAsString.replaceFirst("KURA_PAIRWISE", "NONE"); } else { throw KuraException.internalError( "Failed to generate wpa_supplicant.conf -- Invalid mode: " + wifiConfig.getMode()); } // Remove the 'wheel' group assignment for Yocto image on Raspberry_Pi if (OS_VERSION.equals(KuraConstants.Raspberry_Pi.getImageName())) { fileAsString = fileAsString.replaceFirst("ctrl_interface_group=wheel", "#ctrl_interface_group=wheel"); } // replace the necessary components fileAsString = fileAsString.replaceFirst("KURA_MODE", Integer.toString(getSupplicantMode(wifiConfig.getMode()))); if (wifiConfig.getSSID() != null) { fileAsString = fileAsString.replaceFirst("KURA_ESSID", wifiConfig.getSSID()); } else { throw KuraException.internalError("the essid can not be null"); } String passKey = new String(wifiConfig.getPasskey().getPassword()); if (passKey != null && passKey.trim().length() > 0) { if (passKey.length() < 8 || passKey.length() > 63) { throw KuraException.internalError( "the WPA passphrase (passwd) must be between 8 (inclusive) and 63 (inclusive) characters in length: " + passKey); } else { fileAsString = fileAsString.replaceFirst("KURA_PASSPHRASE", passKey.trim()); } } else { throw KuraException.internalError("the passwd can not be null"); } if (wifiConfig.getSecurity() == WifiSecurity.SECURITY_WPA) { fileAsString = fileAsString.replaceFirst("KURA_PROTO", "WPA"); } else if (wifiConfig.getSecurity() == WifiSecurity.SECURITY_WPA2) { fileAsString = fileAsString.replaceFirst("KURA_PROTO", "RSN"); } else if (wifiConfig.getSecurity() == WifiSecurity.SECURITY_WPA_WPA2) { fileAsString = fileAsString.replaceFirst("KURA_PROTO", "WPA RSN"); } else { fileAsString = fileAsString.replaceFirst("KURA_PROTO", "WPA RSN"); } if (wifiConfig.getPairwiseCiphers() != null) { fileAsString = fileAsString.replaceFirst("KURA_PAIRWISE", WifiCiphers.toString(wifiConfig.getPairwiseCiphers())); } else { fileAsString = fileAsString.replaceFirst("KURA_PAIRWISE", "CCMP TKIP"); } if (wifiConfig.getGroupCiphers() != null) { fileAsString = fileAsString.replaceFirst("KURA_GROUP", WifiCiphers.toString(wifiConfig.getGroupCiphers())); } else { fileAsString = fileAsString.replaceFirst("KURA_GROUP", "CCMP TKIP"); } if (wifiConfig.getBgscan() != null) { fileAsString = fileAsString.replaceFirst("KURA_BGSCAN", wifiConfig.getBgscan().toString()); } else { fileAsString = fileAsString.replaceFirst("KURA_BGSCAN", ""); } fileAsString = fileAsString.replaceFirst("KURA_SCANFREQ", getScanFrequenciesMHz(wifiConfig.getChannels())); // everything is set and we haven't failed - write the file copyFile(fileAsString, outputFile); return; } else if (wifiConfig.getSecurity() == WifiSecurity.SECURITY_NONE || wifiConfig.getSecurity() == WifiSecurity.NONE) { File outputFile = new File(configFile); String fileAsString = null; if (wifiConfig.getMode() == WifiMode.INFRA) { fileAsString = IOUtil.readResource(FrameworkUtil.getBundle(getClass()), "/src/main/resources/wifi/wpasupplicant.conf_open"); } else if (wifiConfig.getMode() == WifiMode.ADHOC) { fileAsString = IOUtil.readResource(FrameworkUtil.getBundle(getClass()), "/src/main/resources/wifi/wpasupplicant.conf_adhoc_open"); fileAsString = fileAsString.replaceFirst("KURA_FREQUENCY", Integer.toString(WpaSupplicantUtil.convChannelToFrequency(wifiConfig.getChannels()[0]))); } else { throw KuraException.internalError( "Failed to generate wpa_supplicant.conf -- Invalid mode: " + wifiConfig.getMode()); } // Remove the 'wheel' group assignment for Yocto image on Raspberry_Pi if (OS_VERSION.equals(KuraConstants.Raspberry_Pi.getImageName())) { fileAsString = fileAsString.replaceFirst("ctrl_interface_group=wheel", "#ctrl_interface_group=wheel"); } // replace the necessary components fileAsString = fileAsString.replaceFirst("KURA_MODE", Integer.toString(getSupplicantMode(wifiConfig.getMode()))); if (wifiConfig.getSSID() != null) { fileAsString = fileAsString.replaceFirst("KURA_ESSID", wifiConfig.getSSID()); } else { throw KuraException.internalError("the essid can not be null"); } if (wifiConfig.getBgscan() != null) { fileAsString = fileAsString.replaceFirst("KURA_BGSCAN", wifiConfig.getBgscan().toString()); } else { fileAsString = fileAsString.replaceFirst("KURA_BGSCAN", ""); } fileAsString = fileAsString.replaceFirst("KURA_SCANFREQ", getScanFrequenciesMHz(wifiConfig.getChannels())); // everything is set and we haven't failed - write the file copyFile(fileAsString, outputFile); return; } else { throw KuraException.internalError("unsupported security type: " + wifiConfig.getSecurity()); } } private void moveWpaSupplicantConf(String ifaceName, String configFile) throws KuraException { File outputFile = new File(configFile); File wpaConfigFile = new File(WpaSupplicantManager.getWpaSupplicantConfigFilename(ifaceName)); try { if (!FileUtils.contentEquals(outputFile, wpaConfigFile)) { if (outputFile.renameTo(wpaConfigFile)) { s_logger.trace("Successfully wrote wpa_supplicant config file"); } else { s_logger.error("Failed to write wpa_supplicant config file"); throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, "error while building up new configuration file for wpa_supplicant config"); } } else { s_logger.info("Not rewriting wpa_supplicant.conf file because it is the same"); } } catch (IOException e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, "error while building up new configuration file for wpa_supplicant config"); } } /* * This method copies supplied String to a file */ private void copyFile(String data, File destination) throws KuraException { FileOutputStream fos = null; PrintWriter pw = null; try { fos = new FileOutputStream(destination); pw = new PrintWriter(fos); pw.write(data); pw.flush(); fos.getFD().sync(); setPermissions(destination.toString()); } catch (IOException e) { throw KuraException.internalError(e); } finally { if (fos != null) { try { fos.close(); } catch (IOException ex) { s_logger.error("I/O Exception while closing FileOutputStream!"); } } if (pw != null) { pw.close(); } } } /* * This method sets permissions to the wpa_supplicant configuration file */ private void setPermissions(String fileName) throws KuraException { SafeProcess procChmod = null; SafeProcess procDos = null; try { procChmod = ProcessUtil.exec("chmod 600 " + fileName); procChmod.waitFor(); procDos = ProcessUtil.exec("dos2unix " + fileName); procDos.waitFor(); } catch (Exception e) { throw KuraException.internalError(e); } finally { if (procChmod != null) { ProcessUtil.destroy(procChmod); } if (procDos != null) { ProcessUtil.destroy(procDos); } } } // /* // * This method reads supplied input stream into a string // */ // private static String readInputStreamAsString(InputStream is) throws IOException { // BufferedInputStream bis = new BufferedInputStream(is); // ByteArrayOutputStream buf = new ByteArrayOutputStream(); // int result = bis.read(); // while (result != -1) { // byte b = (byte) result; // buf.write(b); // result = bis.read(); // } // return buf.toString(); // } /* * This method converts the supplied string to hex */ private String toHex(String s) { if (s == null) { return null; } byte[] raw = s.getBytes(); StringBuffer hex = new StringBuffer(2 * raw.length); for (byte element : raw) { hex.append(HEXES.charAt((element & 0xF0) >> 4)).append(HEXES.charAt(element & 0x0F)); } return hex.toString(); } /* * This method returns the supplicant mode */ private static int getSupplicantMode(WifiMode mode) { if (mode == WifiMode.ADHOC) { return WpaSupplicantUtil.MODE_IBSS; } else if (mode == WifiMode.MASTER) { return WpaSupplicantUtil.MODE_AP; } else { return WpaSupplicantUtil.MODE_INFRA; } } /* * This method returns a list of frequencies based on a list of channels */ private String getScanFrequenciesMHz(int[] channels) { StringBuffer sbFrequencies = new StringBuffer(); if (channels != null && channels.length > 0) { for (int i = 0; i < channels.length; i++) { sbFrequencies.append(WpaSupplicantUtil.convChannelToFrequency(channels[i])); if (i < channels.length - 1) { sbFrequencies.append(' '); } } } else { for (int i = 1; i <= 13; i++) { sbFrequencies.append(WpaSupplicantUtil.convChannelToFrequency(i)); if (i < 13) { sbFrequencies.append(' '); } } } return sbFrequencies.toString(); } }