diff --git a/gestion/chgpass.py b/gestion/chgpass.py index c447075c..cc71a7bc 100755 --- a/gestion/chgpass.py +++ b/gestion/chgpass.py @@ -18,10 +18,11 @@ Copyright (C) Frédéric Pauget Licence : GPLv2 """ +import subprocess import getpass, commands, os, sys, base64, syslog from user_tests import getuser, isadm -from affich_tools import cprint +from affich_tools import cprint, coul import secrets_new as secrets try: ldap_password = secrets.get("ldap_password") @@ -51,6 +52,57 @@ def chgpass(dn, mdp = None) : else : cprint(u'Changement effectué avec succès', u'vert') +def checkpass(mdp, dialog=False, longueur=8): + ### Test du mdp + ## 1 - Longueur + if len(mdp) < longueur : + return False, coul(u'Mot de passe trop court, il doit faire au moins %s caractères de long' % longueur, 'rouge', dialog=dialog) + + ## 2 - Empeche les mots de passe non ASCII + try: + mdp = mdp.encode('ascii') + except (UnicodeEncodeError, UnicodeDecodeError): + return False, coul(u'Les accents ou caractères bizarres ne sont pas autorisés (mais #!@*&%{}| le sont !)', + 'rouge', dialog=dialog) + + + ## 2bis - On évite une attaque de type injection de code shell + if "'" in mdp: + return False, coul(u'Les accents ou caractères bizarres ne sont pas autorisés (mais #!@*&%{}| le sont !)', + 'rouge', dialog=dialog) + + ## 3 - assez de caractères de types différents ? + chiffres = 0 + majuscules = 0 + minuscules = 0 + autres = 0 + for c in mdp[:] : + if c.isdigit() : + # Un chiffre rapporte 1.5 point avec un maximum de 5 + if chiffres < 4.5 : chiffres += 1.5 + elif c.islower() : + if minuscules < 3 : minuscules += 1 + elif c.isupper() : + if majuscules < 3 : majuscules += 1 + else : + autres += 4 + if (not majuscules and not minuscules): + return False, coul(u'Mot de passe sans majuscules et sans miniscules. Mélangez des deux ?') + if len(mdp) < 16 - minuscules - majuscules - chiffres - autres: + return False, coul(u'Mot de passe trop simple. Ajoutez des chiffres ou des caractères parmis #!@*&%{}| ou mélangez des majuscules/minuscules ?', 'rouge', dialog=dialog) + + ## 4 - Cracklib + p = subprocess.Popen(['/usr/sbin/cracklib-check'], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) + (test, err) = p.communicate(input=mdp) + if test.split(':')[-1].lower().strip() != 'ok' : + commentaire = { + ' it does not contain enough DIFFERENT characters': u'Il y a trop de caractères identiques.' , + ' it is based on a dictionary word': u'Le mot de passe est basé sur un mot du dictionnaire' , + ' it is too simplistic/systematic': u'Le mot de passe est trop simple/répétitif' + }.get(test.split(':')[-1],test.split(':')[-1]) + return False, coul(commentaire, 'rouge') + + return True, "" def promptpass(dn): cprint(u"""Le nouveau mot de passe doit comporter au minimum 6 caractères. @@ -63,55 +115,9 @@ Il ne doit pas être basé sur un mot du dictionnaire.""", 'jaune') while 1 : mdp = getpass.getpass('Nouveau mot de passe : ') - ### Test du mdp - ## 1 - Longueur - if len(mdp) < 6 : - cprint(u'Mot de passe trop court', 'rouge') - continue - - ## 2 - Empeche les mots de passe non ASCII - try: - mdp = mdp.encode('ascii') - except (UnicodeEncodeError, UnicodeDecodeError): - cprint(u'Les accents ou caractères bizarres ne sont pas autorisés (mais #!@*&%{}| le sont !)', - 'rouge') - continue - - ## 2bis - On évite une attaque de type injection de code shell - if "'" in mdp: - cprint(u'Les accents ou caractères bizarres ne sont pas autorisés (mais #!@*&%{}| le sont !)', - 'rouge') - continue - - ## 3 - assez de caractères de types différents ? - chiffres = 0 - majuscules = 0 - minuscules = 0 - autres = 0 - for c in mdp[:] : - if c.isdigit() : - # Un chiffre rapporte 1.5 point avec un maximum de 5 - if chiffres < 4.5 : chiffres += 1.5 - elif c.islower() : - if minuscules < 3 : minuscules += 1 - elif c.isupper() : - if majuscules < 3 : majuscules += 1 - else : - autres += 4 - if len(mdp) < 16 - minuscules - majuscules - chiffres - autres or \ - (not majuscules and not minuscules) : - cprint(u'Mot de passe trop simple.', 'rouge') - continue - - ## 4 - Cracklib - test = commands.getoutput("echo '%s' | /usr/sbin/cracklib-check" % mdp) - if test.split(':')[-1].lower() != ' ok' : - commentaire = { - ' it does not contain enough DIFFERENT characters': u'Il y a trop de caractères identiques.' , - ' it is based on a dictionary word': u'Le mot de passe est basé sur un mot du dictionnaire' , - ' it is too simplistic/systematic': u'Le mot de passe est trop simple/répétitif' - }.get(test.split(':')[-1],test.split(':')[-1]) - cprint(commentaire, 'rouge') + (good, txt) = checkpass(mdp) + if not good: + print txt continue ### On redemande le mot de passe