Screens/NetworkSetup.py, SystemPlugins/WirelessLan,Networkwizard: dont use "hidden...
[enigma2.git] / lib / python / Plugins / SystemPlugins / WirelessLan / plugin.py
1 from enigma import eTimer, eTPM, eEnv
2 from Screens.Screen import Screen
3 from Components.ActionMap import ActionMap, NumberActionMap
4 from Components.Pixmap import Pixmap,MultiPixmap
5 from Components.Label import Label
6 from Components.Sources.StaticText import StaticText
7 from Components.Sources.List import List
8 from Components.MenuList import MenuList
9 from Components.config import config, getConfigListEntry, ConfigYesNo, NoSave, ConfigSubsection, ConfigText, ConfigSelection, ConfigPassword
10 from Components.ConfigList import ConfigListScreen
11 from Components.Network import iNetwork
12 from Components.Console import Console
13 from Plugins.Plugin import PluginDescriptor
14 from os import system, path as os_path, listdir
15 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE
16 from Tools.LoadPixmap import LoadPixmap
17 from Tools.HardwareInfo import HardwareInfo
18 from Wlan import iWlan, wpaSupplicant, iStatus, getWlanConfigName
19 import hashlib
20 from time import time
21 from os import urandom, system
22
23 plugin_path = eEnv.resolve("${libdir}/enigma2/python/Plugins/SystemPlugins/WirelessLan")
24
25
26 list = []
27 list.append("WEP")
28 list.append("WPA")
29 list.append("WPA2")
30 list.append("WPA/WPA2")
31
32 weplist = []
33 weplist.append("ASCII")
34 weplist.append("HEX")
35
36 config.plugins.wlan = ConfigSubsection()
37 config.plugins.wlan.essid = NoSave(ConfigText(default = "home", fixed_size = False))
38 config.plugins.wlan.hiddenessid = NoSave(ConfigYesNo(default = False))
39
40 config.plugins.wlan.encryption = ConfigSubsection()
41 config.plugins.wlan.encryption.enabled = NoSave(ConfigYesNo(default = False))
42 config.plugins.wlan.encryption.type = NoSave(ConfigSelection(list, default = "WPA/WPA2" ))
43 config.plugins.wlan.encryption.wepkeytype = NoSave(ConfigSelection(weplist, default = "ASCII"))
44 config.plugins.wlan.encryption.psk = NoSave(ConfigPassword(default = "mysecurewlan", fixed_size = False))
45
46
47 class WlanStatus(Screen):
48         skin = """
49                 <screen name="WlanStatus" position="center,center" size="560,400" title="Wireless Network State" >
50                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
51                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
52         
53                         <widget source="LabelBSSID" render="Label" position="10,60" size="250,25" valign="left" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
54                         <widget source="LabelESSID" render="Label" position="10,100" size="250,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
55                         <widget source="LabelQuality" render="Label" position="10,140" size="250,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
56                         <widget source="LabelSignal" render="Label" position="10,180" size="250,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
57                         <widget source="LabelBitrate" render="Label" position="10,220" size="250,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
58                         <widget source="LabelEnc" render="Label" position="10,260" size="250,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
59                         
60                         <widget source="BSSID" render="Label" position="320,60" size="180,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
61                         <widget source="ESSID" render="Label" position="320,100" size="180,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
62                         <widget source="quality" render="Label" position="320,140" size="180,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
63                         <widget source="signal" render="Label" position="320,180" size="180,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
64                         <widget source="bitrate" render="Label" position="320,220" size="180,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
65                         <widget source="enc" render="Label" position="320,260" size="180,25" valign="center" font="Regular;20" transparent="1" foregroundColor="#FFFFFF" />
66         
67                         <ePixmap pixmap="skin_default/div-h.png" position="0,350" zPosition="1" size="560,2" />         
68                         <widget source="IFtext" render="Label" position="10,355" size="120,21" zPosition="10" font="Regular;20" halign="left" backgroundColor="#25062748" transparent="1" />
69                         <widget source="IF" render="Label" position="120,355" size="400,21" zPosition="10" font="Regular;20" halign="left" backgroundColor="#25062748" transparent="1" />
70                         <widget source="Statustext" render="Label" position="10,375" size="115,21" zPosition="10" font="Regular;20" halign="left" backgroundColor="#25062748" transparent="1"/>
71                         <widget name="statuspic" pixmaps="skin_default/buttons/button_green.png,skin_default/buttons/button_green_off.png" position="130,380" zPosition="10" size="15,16" transparent="1" alphatest="on"/>
72                 </screen>"""
73         
74         def __init__(self, session, iface):
75                 Screen.__init__(self, session)
76                 self.session = session
77                 self.iface = iface
78                                     
79                 self["LabelBSSID"] = StaticText(_('Accesspoint:'))
80                 self["LabelESSID"] = StaticText(_('SSID:'))
81                 self["LabelQuality"] = StaticText(_('Link Quality:'))
82                 self["LabelSignal"] = StaticText(_('Signal Strength:'))
83                 self["LabelBitrate"] = StaticText(_('Bitrate:'))
84                 self["LabelEnc"] = StaticText(_('Encryption:'))
85                         
86                 self["BSSID"] = StaticText()
87                 self["ESSID"] = StaticText()
88                 self["quality"] = StaticText()
89                 self["signal"] = StaticText()
90                 self["bitrate"] = StaticText()
91                 self["enc"] = StaticText()
92
93                 self["IFtext"] = StaticText()
94                 self["IF"] = StaticText()
95                 self["Statustext"] = StaticText()
96                 self["statuspic"] = MultiPixmap()
97                 self["statuspic"].hide()
98                 self["key_red"] = StaticText(_("Close"))
99
100                 self.resetList()
101                 self.updateStatusbar()
102                 
103                 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "EPGSelectActions", "ShortcutActions"],
104                 {
105                         "ok": self.exit,
106                         "back": self.exit,
107                         "red": self.exit,
108                 }, -1)
109                 self.timer = eTimer()
110                 self.timer.timeout.get().append(self.resetList) 
111                 self.onShown.append(lambda: self.timer.start(5000))
112                 self.onLayoutFinish.append(self.layoutFinished)
113                 self.onClose.append(self.cleanup)
114
115         def cleanup(self):
116                 iStatus.stopWlanConsole()
117                 
118         def layoutFinished(self):
119                 self.setTitle(_("Wireless Network State"))
120                 
121         def resetList(self):
122                 iStatus.getDataForInterface(self.iface,self.getInfoCB)
123                 
124         def getInfoCB(self,data,status):
125                 if data is not None:
126                         if data is True:
127                                 if status is not None:
128                                         self["BSSID"].setText(status[self.iface]["acesspoint"])
129                                         self["ESSID"].setText(status[self.iface]["essid"])
130                                         self["quality"].setText(status[self.iface]["quality"])
131                                         self["signal"].setText(status[self.iface]["signal"])
132                                         self["bitrate"].setText(status[self.iface]["bitrate"])
133                                         self["enc"].setText(status[self.iface]["encryption"])
134                                         self.updateStatusLink(status)
135
136         def exit(self):
137                 self.timer.stop()
138                 self.close(True)        
139
140         def updateStatusbar(self):
141                 self["BSSID"].setText(_("Please wait..."))
142                 self["ESSID"].setText(_("Please wait..."))
143                 self["quality"].setText(_("Please wait..."))
144                 self["signal"].setText(_("Please wait..."))
145                 self["bitrate"].setText(_("Please wait..."))
146                 self["enc"].setText(_("Please wait..."))
147                 self["IFtext"].setText(_("Network:"))
148                 self["IF"].setText(iNetwork.getFriendlyAdapterName(self.iface))
149                 self["Statustext"].setText(_("Link:"))
150
151         def updateStatusLink(self,status):
152                 if status is not None:
153                         if status[self.iface]["acesspoint"] == "No Connection" or status[self.iface]["acesspoint"] == "Not-Associated" or status[self.iface]["acesspoint"] == False:
154                                 self["statuspic"].setPixmapNum(1)
155                         else:
156                                 self["statuspic"].setPixmapNum(0)
157                         self["statuspic"].show()                
158
159
160 class WlanScan(Screen):
161         skin = """
162                 <screen name="WlanScan" position="center,center" size="560,400" title="Choose a Wireless Network" >
163                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
164                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
165                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
166                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
167                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
168                         <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
169                         <widget source="list" render="Listbox" position="5,40" size="550,300" scrollbarMode="showOnDemand">
170                                 <convert type="TemplatedMultiContent">
171                                         {"template": [
172                                                         MultiContentEntryText(pos = (0, 0), size = (550, 30), font=0, flags = RT_HALIGN_LEFT, text = 0), # index 0 is the essid
173                                                         MultiContentEntryText(pos = (0, 30), size = (175, 20), font=1, flags = RT_HALIGN_LEFT, text = 5), # index 5 is the interface
174                                                         MultiContentEntryText(pos = (175, 30), size = (175, 20), font=1, flags = RT_HALIGN_LEFT, text = 4), # index 0 is the encryption
175                                                         MultiContentEntryText(pos = (350, 0), size = (200, 20), font=1, flags = RT_HALIGN_LEFT, text = 2), # index 0 is the signal
176                                                         MultiContentEntryText(pos = (350, 30), size = (200, 20), font=1, flags = RT_HALIGN_LEFT, text = 3), # index 0 is the maxrate
177                                                         MultiContentEntryPixmapAlphaTest(pos = (0, 52), size = (550, 2), png = 6), # index 6 is the div pixmap
178                                                 ],
179                                         "fonts": [gFont("Regular", 28),gFont("Regular", 18)],
180                                         "itemHeight": 54
181                                         }
182                                 </convert>
183                         </widget>
184                         <ePixmap pixmap="skin_default/div-h.png" position="0,340" zPosition="1" size="560,2" />         
185                         <widget source="info" render="Label" position="0,350" size="560,50" font="Regular;24" halign="center" valign="center" backgroundColor="#25062748" transparent="1" />
186                 </screen>"""
187
188         def __init__(self, session, iface):
189                 Screen.__init__(self, session)
190                 self.session = session
191                 self.iface = iface
192                 self.skin_path = plugin_path
193                 self.oldInterfaceState = iNetwork.getAdapterAttribute(self.iface, "up")
194                 self.APList = None
195                 self.newAPList = None
196                 self.WlanList = None
197                 self.cleanList = None
198                 self.oldlist = {}
199                 self.listLength = None
200                 self.rescanTimer = eTimer()
201                 self.rescanTimer.callback.append(self.rescanTimerFired)
202                 
203                 self["info"] = StaticText()
204                 
205                 self.list = []
206                 self["list"] = List(self.list)
207                 
208                 self["key_red"] = StaticText(_("Close"))
209                 self["key_green"] = StaticText(_("Connect"))
210                 self["key_yellow"] = StaticText()
211                         
212                 self["actions"] = NumberActionMap(["WizardActions", "InputActions", "EPGSelectActions"],
213                 {
214                         "ok": self.select,
215                         "back": self.cancel,
216                 }, -1)
217                 
218                 self["shortcuts"] = ActionMap(["ShortcutActions"],
219                 {
220                         "red": self.cancel,
221                         "green": self.select,
222                 })
223                 iWlan.setInterface(self.iface)
224                 self.w = iWlan.getInterface()
225                 self.onLayoutFinish.append(self.layoutFinished)
226                 self.getAccessPoints(refresh = False)
227                 
228         def layoutFinished(self):
229                 self.setTitle(_("Choose a wireless network"))
230         
231         def select(self):
232                 cur = self["list"].getCurrent()
233                 if cur is not None:
234                         iWlan.stopGetNetworkList()
235                         self.rescanTimer.stop()
236                         del self.rescanTimer
237                         if cur[1] is not None:
238                                 if cur[1] == '<hidden>':
239                                         essid = cur[1]
240                                 else:
241                                         essid = cur[0]
242                                 self.close(essid,self.getWlanList())
243                         else:
244                                 self.close(None,None)
245                 else:
246                         iWlan.stopGetNetworkList()
247                         self.rescanTimer.stop()
248                         del self.rescanTimer
249                         self.close(None,None)
250         
251         def cancel(self):
252                 iWlan.stopGetNetworkList()
253                 self.rescanTimer.stop()
254                 del self.rescanTimer
255                 self.close(None)
256
257         def rescanTimerFired(self):
258                 self.rescanTimer.stop()
259                 self.updateAPList()
260
261         def buildEntryComponent(self, essid, bssid, encrypted, iface, maxrate, signal):
262                 divpng = LoadPixmap(cached=True, path=resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/div-h.png"))
263                 encryption = encrypted and _("Yes") or _("No")
264                 if bssid == '<hidden>':                 
265                         return((essid, bssid, None, None, None, None, divpng))
266                 else:                                   
267                         return((essid, bssid, _("Signal: ") + str(signal), _("Max. Bitrate: ") + str(maxrate), _("Encrypted: ") + encryption, _("Interface: ") + str(iface), divpng))
268
269         def updateAPList(self):
270                 newList = []
271                 newList = self.getAccessPoints(refresh = True)  
272                 self.newAPList = []
273                 tmpList = []
274                 newListIndex = None
275                 currentListEntry = None
276                 currentListIndex = None
277
278                 for ap in self.oldlist.keys():
279                         data = self.oldlist[ap]['data']
280                         if data is not None:
281                                 tmpList.append(data)
282
283                 if len(tmpList):
284                         if "<hidden>" not in tmpList:
285                                 tmpList.append( ( _("enter hidden network SSID"), "<hidden>", True, self.iface, _("unavailable"), "" ) )
286
287                         for entry in tmpList:
288                                 self.newAPList.append(self.buildEntryComponent( entry[0], entry[1], entry[2], entry[3], entry[4], entry[5] ))
289         
290                         currentListEntry = self["list"].getCurrent()
291                         idx = 0
292                         for entry in self.newAPList:
293                                 if entry[0] == currentListEntry[0]:
294                                         newListIndex = idx
295                                 idx +=1
296                         self['list'].setList(self.newAPList)
297                         self["list"].setIndex(newListIndex)
298                         self["list"].updateList(self.newAPList)
299                         self.listLength = len(self.newAPList)
300                         self.buildWlanList()
301                         self.setInfo()
302
303         def getAccessPoints(self, refresh = False):
304                 self.APList = []
305                 self.cleanList = []
306                 aps = iWlan.getNetworkList()
307                 if aps is not None:
308                         print "[WirelessLan.py] got Accespoints!"
309                         tmpList = []
310                         compList = []
311                         for ap in aps:
312                                 a = aps[ap]
313                                 if a['active']:
314                                         tmpList.append( (a['essid'], a['bssid']) )
315                                         compList.append( (a['essid'], a['bssid'], a['encrypted'], a['iface'], a['maxrate'], a['signal']) )
316
317                         for entry in tmpList:
318                                 if entry[0] == "":
319                                         for compentry in compList:
320                                                 if compentry[1] == entry[1]:
321                                                         compList.remove(compentry)
322                         for entry in compList:
323                                 self.cleanList.append( ( entry[0], entry[1], entry[2], entry[3], entry[4], entry[5] ) )
324                                 if not self.oldlist.has_key(entry[0]):
325                                         self.oldlist[entry[0]] = { 'data': entry }
326                                 else:
327                                         self.oldlist[entry[0]]['data'] = entry
328                 
329                 if "<hidden>" not in self.cleanList:
330                         self.cleanList.append( ( _("enter hidden network SSID"), "<hidden>", True, self.iface, _("unavailable"), "" ) )
331
332                 for entry in self.cleanList:
333                         self.APList.append(self.buildEntryComponent( entry[0], entry[1], entry[2], entry[3], entry[4], entry[5] ))
334                 
335                 if refresh is False:
336                         self['list'].setList(self.APList)
337                 self.listLength = len(self.APList)
338                 self.setInfo()
339                 self.rescanTimer.start(5000)
340                 return self.cleanList
341
342         def setInfo(self):
343                 length = self.getLength()
344                 if length <= 1:
345                         self["info"].setText(_("No wireless networks found! Please refresh."))
346                 elif length == 2:
347                         self["info"].setText(_("1 wireless network found!"))
348                 else:
349                         self["info"].setText(str(length-1)+_(" wireless networks found!"))
350
351         def buildWlanList(self):
352                 self.WlanList = []
353                 for entry in self['list'].list:
354                         if entry[1] == "<hidden>":
355                                 continue
356                         else:
357                                 self.WlanList.append( (entry[0], entry[0]) )
358
359         def getLength(self):
360                 return self.listLength          
361
362         def getWlanList(self):
363                 if self.WlanList is None:
364                         self.buildWlanList()
365                 return self.WlanList
366
367
368 def bin2long(s):
369         return reduce( lambda x,y:(x<<8L)+y, map(ord, s))
370
371 def long2bin(l):
372         res = ""
373         for byte in range(128):
374                 res += chr((l >> (1024 - (byte + 1) * 8)) & 0xff)
375         return res
376
377 def rsa_pub1024(src, mod):
378         return long2bin(pow(bin2long(src), 65537, bin2long(mod)))
379         
380 def decrypt_block(src, mod):
381         if len(src) != 128 and len(src) != 202:
382                 return None
383         dest = rsa_pub1024(src[:128], mod)
384         hash = hashlib.sha1(dest[1:107])
385         if len(src) == 202:
386                 hash.update(src[131:192])       
387         result = hash.digest()
388         if result == dest[107:127]:
389                 return dest
390         return None
391
392 def validate_certificate(cert, key):
393         buf = decrypt_block(cert[8:], key) 
394         if buf is None:
395                 return None
396         return buf[36:107] + cert[139:196]
397
398 def get_random():
399         try:
400                 xor = lambda a,b: ''.join(chr(ord(c)^ord(d)) for c,d in zip(a,b*100))
401                 random = urandom(8)
402                 x = str(time())[-8:]
403                 result = xor(random, x)
404                                 
405                 return result
406         except:
407                 return None
408
409 def WlanStatusScreenMain(session, iface):
410         session.open(WlanStatus, iface)
411
412 def callFunction(iface):
413         iWlan.setInterface(iface)
414         i = iWlan.getWirelessInterfaces()
415         if i:
416                 if iface in i or iNetwork.isWirelessInterface(iface):
417                         return WlanStatusScreenMain
418                 return None
419         return None
420
421 def configStrings(iface):
422         hardware_info = HardwareInfo()
423         if  hardware_info.device_name != "dm7025":
424                 rootkey = ['\x9f', '|', '\xe4', 'G', '\xc9', '\xb4', '\xf4', '#', '&', '\xce', '\xb3', '\xfe', '\xda', '\xc9', 'U', '`', '\xd8', '\x8c', 's', 'o', '\x90', '\x9b', '\\', 'b', '\xc0', '\x89', '\xd1', '\x8c', '\x9e', 'J', 'T', '\xc5', 'X', '\xa1', '\xb8', '\x13', '5', 'E', '\x02', '\xc9', '\xb2', '\xe6', 't', '\x89', '\xde', '\xcd', '\x9d', '\x11', '\xdd', '\xc7', '\xf4', '\xe4', '\xe4', '\xbc', '\xdb', '\x9c', '\xea', '}', '\xad', '\xda', 't', 'r', '\x9b', '\xdc', '\xbc', '\x18', '3', '\xe7', '\xaf', '|', '\xae', '\x0c', '\xe3', '\xb5', '\x84', '\x8d', '\r', '\x8d', '\x9d', '2', '\xd0', '\xce', '\xd5', 'q', '\t', '\x84', 'c', '\xa8', ')', '\x99', '\xdc', '<', '"', 'x', '\xe8', '\x87', '\x8f', '\x02', ';', 'S', 'm', '\xd5', '\xf0', '\xa3', '_', '\xb7', 'T', '\t', '\xde', '\xa7', '\xf1', '\xc9', '\xae', '\x8a', '\xd7', '\xd2', '\xcf', '\xb2', '.', '\x13', '\xfb', '\xac', 'j', '\xdf', '\xb1', '\x1d', ':', '?']
425                 etpm = eTPM()
426                 l2cert = etpm.getCert(eTPM.TPMD_DT_LEVEL2_CERT)
427                 if l2cert is None:
428                         return
429                 l2key = validate_certificate(l2cert, rootkey)
430                 if l2key is None:
431                         return
432                 l3cert = etpm.getCert(eTPM.TPMD_DT_LEVEL3_CERT)
433                 if l3cert is None:
434                         return
435                 l3key = validate_certificate(l3cert, l2key)
436                 if l3key is None:
437                         return
438                 rnd = get_random()
439                 if rnd is None:
440                         return
441                 val = etpm.challenge(rnd)
442                 result = decrypt_block(val, l3key)
443         if hardware_info.device_name == "dm7025" or result[80:88] == rnd:
444                 driver = iNetwork.detectWlanModule(iface)
445         else:
446                 driver = 'dreambox'
447         print 'Using "%s" as wpa-supplicant driver' % (driver)
448         ret = ""
449         if driver == 'madwifi' and config.plugins.wlan.hiddenessid.value:
450                 ret += "\tpre-up iwconfig " + iface + " essid \"" + config.plugins.wlan.essid.value + "\" || true\n"
451         ret += "\tpre-up wpa_supplicant -i" + iface + " -c" + getWlanConfigName(iface) + " -B -dd -D" + driver + " || true\n"
452         ret += "\tpre-down wpa_cli -i" + iface + " terminate || true\n"
453         return ret
454
455 def Plugins(**kwargs):
456         return PluginDescriptor(name=_("Wireless LAN"), description=_("Connect to a Wireless Network"), where = PluginDescriptor.WHERE_NETWORKSETUP, needsRestart = False, fnc={"ifaceSupported": callFunction, "configStrings": configStrings, "WlanPluginEntry": lambda x: "Wireless Network Configuartion..."})