Use built-in python functions for authenticating against unix-accounts
[vuplus_dvbapp-plugin] / webinterface / src / plugin.py
index a805a69..17d61f8 100644 (file)
@@ -8,6 +8,7 @@ from Components.Network import iNetwork
 from Screens.MessageBox import MessageBox
 from WebIfConfig import WebIfConfigScreen
 from WebChilds.Toplevel import getToplevel
+from Tools.HardwareInfo import HardwareInfo
 
 from Tools.Directories import copyfile, resolveFilename, SCOPE_PLUGINS, SCOPE_CONFIG
 
@@ -21,8 +22,10 @@ from OpenSSL import SSL
 from os.path import isfile as os_isfile
 from __init__ import _, __version__, decrypt_block
 from webif import get_random, validate_certificate
+
 tpm = eTPM()
 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', ':', '?']
+hw = HardwareInfo()
 #CONFIG INIT
 
 #init the config
@@ -58,10 +61,10 @@ server.VERSION = "Enigma2 WebInterface Server $Revision$".replace("$Revi", "").r
 #===============================================================================
 class Closer:
        counter = 0
-       def __init__(self, session, callback=None):
+       def __init__(self, session, callback=None, l2k=None):
                self.callback = callback
                self.session = session
-
+               self.l2k = l2k
 #===============================================================================
 # Closes all running Instances of the Webinterface
 #===============================================================================
@@ -79,7 +82,7 @@ class Closer:
                running_defered = []
                if self.counter < 1:
                        if self.callback is not None:
-                               self.callback(self.session)
+                               self.callback(self.session, self.l2k)
 
 #===============================================================================
 # #Is it already down?
@@ -88,7 +91,7 @@ class Closer:
                self.counter -= 1
                if self.counter < 1:
                        if self.callback is not None:
-                               self.callback(self.session)
+                               self.callback(self.session, self.l2k)
 
 def checkCertificates():
        print "[WebInterface] checking for SSL Certificates"
@@ -102,7 +105,7 @@ def checkCertificates():
        else:
                return True
                
-def installCertificates(session, callback = None):
+def installCertificates(session, callback = None, l2k = None):
        print "[WebInterface] Installing SSL Certificates to %s" %resolveFilename(SCOPE_CONFIG)
        
        srvcert = '%sserver.pem' %resolveFilename(SCOPE_CONFIG) 
@@ -119,14 +122,14 @@ def installCertificates(session, callback = None):
                ret = copyfile(source, target)
                
                if ret == 0 and callback != None:
-                       callback(session)
+                       callback(session, l2k)
        
        if ret < 0:
                config.plugins.Webinterface.https.enabled.value = False
                config.plugins.Webinterface.https.enabled.save()
                
                # Start without https
-               callback(session)
+               callback(session, l2k)
                
                #Inform the user
                session.open(MessageBox, "Couldn't install SSL-Certifactes for https access\nHttps access is now disabled!", MessageBox.TYPE_ERROR)
@@ -134,7 +137,7 @@ def installCertificates(session, callback = None):
 #===============================================================================
 # restart the Webinterface for all configured Interfaces
 #===============================================================================
-def restartWebserver(session):
+def restartWebserver(session, l2k):
        try:
                del session.mediaplayer
                del session.messageboxanswer
@@ -145,9 +148,9 @@ def restartWebserver(session):
 
        global running_defered
        if len(running_defered) > 0:
-               Closer(session, startWebserver).stop()
+               Closer(session, startWebserver, l2k).stop()
        else:
-               startWebserver(session)
+               startWebserver(session, l2k)
        
 #===============================================================================
 # start the Webinterface for all configured Interfaces
@@ -173,7 +176,7 @@ def startWebserver(session, l2k):
                if config.plugins.Webinterface.https.enabled.value:
                        if not checkCertificates():
                                print "[Webinterface] Installing Webserver Certificates for SSL encryption"
-                               installCertificates(session, startWebserver)
+                               installCertificates(session, startWebserver, l2k)
                                return
                # Listen on all Interfaces
                ip = "0.0.0.0"
@@ -225,37 +228,30 @@ def stopWebserver(session):
 # on given ipaddress, port, w/o auth, w/o ssl
 #===============================================================================
 def startServerInstance(session, ipaddress, port, useauth=False, l2k=None, usessl=False):
-       #try:
-       l3k = None              
-       l3c = tpm.getCert(eTPM.TPMD_DT_LEVEL3_CERT)
-       
-       if l3c is None:
-               print "random error"
-               return False                    
-       
-       l3k = validate_certificate(l3c, l2k)
-       if l3k is None:
-               print "random error"                    
-               return False
-       
-       random = get_random()
-       if random is None:
-               print "random error"
-               return False
-       
-       value = tpm.challenge(random)
-       result = decrypt_block(value, l3k)
+       if hw.get_device_name().lower() != "dm7025":
+               l3k = None              
+               l3c = tpm.getCert(eTPM.TPMD_DT_LEVEL3_CERT)
+               
+               if l3c is None:
+                       return False                    
+               
+               l3k = validate_certificate(l3c, l2k)
+               if l3k is None:                 
+                       return False
+               
+               random = get_random()
+               if random is None:
+                       return False
        
-       if result is None:
-               print "random error"
-               return False
-       else:
-               if result [80:88] == random:            
-                       print "[WebInterface.plugin].startServerInstance - Genuine verfication succeeded!"
+               value = tpm.challenge(random)
+               result = decrypt_block(value, l3k)
+               
+               if result is None:
+                       return False
                else:
-                       print "random error"
-                       return False    
-       
+                       if result [80:88] != random:            
+                               return False
+               
        if useauth:
 # HTTPAuthResource handles the authentication for every Resource you want it to                        
                root = HTTPAuthResource(toplevel, "Enigma2 WebInterface")
@@ -270,7 +266,7 @@ def startServerInstance(session, ipaddress, port, useauth=False, l2k=None, usess
        else:
                d = reactor.listenTCP(port, site, interface=ipaddress)
        running_defered.append(d)               
-       print "[Webinterface] started on %s:%i" % (ipaddress, port), "auth=", useauth, "ssl=", usessl
+       print "[Webinterface] started on %s:%i auth=%s ssl=%s" % (ipaddress, port, useauth, usessl)
        return True
        
        #except Exception, e:
@@ -308,7 +304,10 @@ class HTTPAuthResource(resource.Resource):
                
                # if the auth-information has not yet been stored to the session
                if not sessionNs.has_key('authenticated'):
-                       sessionNs['authenticated'] = check_passwd(request.getUser(), request.getPassword())
+                       if request.getUser() != '':
+                               sessionNs['authenticated'] = check_passwd(request.getUser(), request.getPassword())
+                       else:
+                               sessionNs['authenticated'] = False
                
                #if the auth-information already is in the session                              
                else:
@@ -356,154 +355,31 @@ class UnauthorizedResource(resource.Resource):
        def render(self, request):      
                return self.errorpage.render(request)
 
-# Password verfication stuff
-
-from hashlib import md5 as md5_new
-from crypt import crypt
 
-#===============================================================================
-# getpwnam
-# 
-# Get a password database entry for the given user name
-# Example from the Python Library Reference.
-#===============================================================================
-def getpwnam(name, pwfile=None):
-       if not pwfile:
-               pwfile = '/etc/passwd'
-
-       f = open(pwfile)
-       while 1:
-               line = f.readline()
-               if not line:
-                       f.close()
-                       raise KeyError, name
-               entry = tuple(line.strip().split(':', 6))
-               if entry[0] == name:
-                       f.close()
-                       return entry
 
-#===============================================================================
-# passcrypt
-#
-# Encrypt a password
-#===============================================================================
-def passcrypt(passwd, salt=None, method='des', magic='$1$'):
-       """Encrypt a string according to rules in crypt(3)."""
-       if method.lower() == 'des':
-               return crypt(passwd, salt)
-       elif method.lower() == 'md5':
-               return passcrypt_md5(passwd, salt, magic)
-       elif method.lower() == 'clear':
-               return passwd
-
-#===============================================================================
-# check_passwd
-#
-# Checks username and Password against a given Unix Password file 
-# The default path is '/etc/passwd'
-#===============================================================================
-def check_passwd(name, passwd, pwfile='/etc/passwd'):
-       """Validate given user, passwd pair against password database."""
+# Password verfication stuff
+from crypt import crypt
+from pwd import getpwnam
+from spwd import getspnam
 
-       if not pwfile or type(pwfile) == type(''):
-               getuser = lambda x, pwfile = pwfile: getpwnam(x, pwfile)[1]
-       else:
-               getuser = pwfile.get_passwd
 
+def check_passwd(name, passwd):
+       cryptedpass = None
        try:
-               enc_passwd = getuser(name)
-       except (KeyError, IOError):
-               print "[Webinterface.check_passwd] No such user!"
+               cryptedpass = getpwnam(name)[1]
+       except:
                return False
-       if not enc_passwd:
-               "[Webinterface.check_passwd] NOT ENC_PASSWD"
-               return False
-       elif len(enc_passwd) >= 3 and enc_passwd[:3] == '$1$':
-               salt = enc_passwd[3:enc_passwd.find('$', 3)]
-               return enc_passwd == passcrypt(passwd, salt, 'md5')
-       else:
-               return enc_passwd == passcrypt(passwd, enc_passwd[:2])
-
-def _to64(v, n):
-       DES_SALT = list('./0123456789' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz')
-       r = ''
-       while (n - 1 >= 0):
-               r = r + DES_SALT[v & 0x3F]
-               v = v >> 6
-               n = n - 1
-       return r
-
-#===============================================================================
-# passcrypt_md5
-# Encrypt a password via md5
-#===============================================================================
-def passcrypt_md5(passwd, salt=None, magic='$1$'):
-       if not salt:
-               pass
-       elif salt[:len(magic)] == magic:
-               # remove magic from salt if present
-               salt = salt[len(magic):]
-
-       # salt only goes up to first '$'
-       salt = salt.split('$')[0]
-       # limit length of salt to 8
-       salt = salt[:8]
-
-       ctx = md5_new(passwd)
-       ctx.update(magic)
-       ctx.update(salt)
-
-       ctx1 = md5_new(passwd)
-       ctx1.update(salt)
-       ctx1.update(passwd)
-
-       final = ctx1.digest()
-
-       for i in range(len(passwd), 0 , -16):
-               if i > 16:
-                       ctx.update(final)
-               else:
-                       ctx.update(final[:i])
-
-       i = len(passwd)
-       while i:
-               if i & 1:
-                       ctx.update('\0')
-               else:
-                       ctx.update(passwd[:1])
-               i = i >> 1
-       final = ctx.digest()
-
-       for i in range(1000):
-               ctx1 = md5_new()
-               if i & 1:
-                       ctx1.update(passwd)
-               else:
-                       ctx1.update(final)
-               if i % 3: ctx1.update(salt)
-               if i % 7: ctx1.update(passwd)
-               if i & 1:
-                       ctx1.update(final)
-               else:
-                       ctx1.update(passwd)
-               final = ctx1.digest()
-
-       rv = magic + salt + '$'
-       final = map(ord, final)
-       l = (final[0] << 16) + (final[6] << 8) + final[12]
-       rv = rv + _to64(l, 4)
-       l = (final[1] << 16) + (final[7] << 8) + final[13]
-       rv = rv + _to64(l, 4)
-       l = (final[2] << 16) + (final[8] << 8) + final[14]
-       rv = rv + _to64(l, 4)
-       l = (final[3] << 16) + (final[9] << 8) + final[15]
-       rv = rv + _to64(l, 4)
-       l = (final[4] << 16) + (final[10] << 8) + final[5]
-       rv = rv + _to64(l, 4)
-       l = final[11]
-       rv = rv + _to64(l, 2)
-
-       return rv
+       
+       if cryptedpass:
+               #shadowed or not, that's the questions here
+               if cryptedpass == 'x' or cryptedpass == '*':
+                       try:
+                               cryptedpass = getspnam(name)[1]
+                       except:
+                               return False                    
+                               
+               return crypt(passwd, cryptedpass) == cryptedpass
+       return False
 
 global_session = None
 
@@ -553,17 +429,21 @@ def checkBonjour():
 #===============================================================================
 def networkstart(reason, **kwargs):
        l2r = False
-       l2c = tpm.getCert(eTPM.TPMD_DT_LEVEL2_CERT)
-       
-       if l2c is None:
-               return
-       
-       l2k = validate_certificate(l2c, rootkey)
-       if l2k is None:
-               return
+       l2k = None
+       if hw.get_device_name().lower() != "dm7025":            
+               l2c = tpm.getCert(eTPM.TPMD_DT_LEVEL2_CERT)
+               
+               if l2c is None:
+                       return
+               
+               l2k = validate_certificate(l2c, rootkey)
+               if l2k is None:
+                       return
+                       
+               l2r = True
+       else:
+               l2r = True
                
-       l2r = True
-       
        if l2r: 
                if reason is True:
                        startWebserver(global_session, l2k)
@@ -571,20 +451,35 @@ def networkstart(reason, **kwargs):
                        
                elif reason is False:
                        stopWebserver(global_session)
-                       checkBonjour()  
-       else:
-               print "random error"
+                       checkBonjour()
                
 def openconfig(session, **kwargs):
        session.openWithCallback(configCB, WebIfConfigScreen)
 
 def configCB(result, session):
-       if result is True:
-               print "[WebIf] config changed"
-               restartWebserver(session)
-               checkBonjour()
+       l2r = False
+       l2k = None
+       if hw.get_device_name().lower() != "dm7025":            
+               l2c = tpm.getCert(eTPM.TPMD_DT_LEVEL2_CERT)
+               
+               if l2c is None:
+                       return
+               
+               l2k = validate_certificate(l2c, rootkey)
+               if l2k is None:
+                       return
+                       
+               l2r = True
        else:
-               print "[WebIf] config not changed"
+               l2r = True
+               
+       if l2r: 
+               if result:
+                       print "[WebIf] config changed"
+                       restartWebserver(session, l2k)
+                       checkBonjour()
+               else:
+                       print "[WebIf] config not changed"
 
 def Plugins(**kwargs):
        return [PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART], fnc=sessionstart),