Commit 22a59154 authored by Daniel Stan's avatar Daniel Stan

Vers une version qui marche

parent 8eb2e3e2
......@@ -2,6 +2,9 @@
# -*- encoding: utf-8 -*-
"""cranspasswords-server.py: Serveur pour cranspasswords"""
MYDIR = '/home/dstan/crans/cranspasswords/'
STORE = '/home/dstan/crans/passwords/v2/'
import glob
import os
import pwd
......@@ -15,7 +18,6 @@ if MYUID == 'root':
KEYS = {
"aza-vallina": ("Damien.Aza-Vallina@crans.org", None),
"dandrimont": ("nicolas.dandrimont@crans.org", "66475AAF"),
"nicolasd": (None, None),
"blockelet": ("blockelet@crans.org", "AF087A52"),
"chambart": ("pierre.chambart@crans.org", "F2530FCE"),
"dimino": ("jdimino@dptinfo.ens-cachan.fr", "2127F85A"),
......@@ -25,8 +27,32 @@ KEYS = {
"lagorce": ("xavier.lagorce@crans.org", "0BF3708E"),
"parret-freaud": ("parret-freaud@crans.org", "7D980513"),
"tvincent": ("vincent.thomas@crans.org", "C5C4ACC0"),
"iffrig": ("iffrig@crans.org","5BEC9A2F"),
"becue": ("becue@crans.org", "194974E2"),
"dstan": ("daniel.stan@crans.org", "6E1C820B"),
"cauderlier": ("cauderlier@crans.org",None), #Méchant pas beau
"maioli": ("maioli@crans.org","9E5026E8")
}
RTC=[
"dandrimont",
"iffrig"
]
NOUNOUS=RTC+[
"blockelet",
"becue",
"dstan",
"chambart",
"dimino",
"durand-gasselin",
"glondu",
"huber",
"lagorce",
"parret-freaud",
"cauderlier",
"maioli"
]
ROLES = {
"bureau": [
"aza-vallina",
......@@ -37,31 +63,19 @@ ROLES = {
"durand-gasselin",
"lagorce",
],
"rtc": [
"dandrimont",
"nicolasd",
],
"nounou": [
"blockelet",
"chambart",
"dandrimont",
"dimino",
"durand-gasselin",
"glondu",
"huber",
"lagorce",
"parret-freaud",
"tvincent",
],
"rtc": RTC,
"nounous": NOUNOUS,
"nounous-w": NOUNOUS #Or maybe RTC ?
}
MYDIR = '/var/local/cranspasswords/'
STORE = MYDIR + 'store/'
def validate(roles):
"""Valide que l'appelant appartient bien aux roles précisés"""
def validate(roles,mode='r'):
"""Valide que l'appelant appartient bien aux roles précisés
Si mode mode='w', recherche un rôle en écriture
"""
for role in roles:
if MYUID in ROLES[role]:
if mode == 'w': role+='-w'
if ROLES.has_key(role) and MYUID in ROLES[role]:
return True
return False
......@@ -127,7 +141,7 @@ def putfile(filename):
except TypeError:
pass
else:
if not validate(oldroles):
if not validate(oldroles,'w'):
return False
writefile(filepath, json.dumps({'roles': roles, 'contents': contents}))
......@@ -140,7 +154,7 @@ def rmfile(filename):
except TypeError:
return True
else:
if validate(roles):
if validate(roles,'w'):
os.remove(getpath(filename))
else:
return False
......
......@@ -5,6 +5,9 @@
import sys
import subprocess
import json
import tempfile
import os
import atexit
######
## GPG Definitions
......@@ -17,6 +20,9 @@ GPG_ARGS = {
'receive-keys': ['--recv-keys'],
}
DEBUG=False
CLIPBOARD=False # Par défaut, place-t-on le mdp dans le presse-papier ?
def gpg(command, args = None):
"""Lance gpg pour la commande donnée avec les arguments
donnés. Renvoie son entrée standard et sa sortie standard."""
......@@ -24,11 +30,19 @@ def gpg(command, args = None):
full_command.extend(GPG_ARGS[command])
if args:
full_command.extend(args)
if DEBUG:
stderr=sys.stderr
else:
stderr=subprocess.PIPE
full_command.extend(['--debug-level=1'])
#print full_command
proc = subprocess.Popen(full_command,
stdin = subprocess.PIPE,
stdout = subprocess.PIPE,
stderr = sys.stderr,
stderr = stderr,
close_fds = True)
if not DEBUG:
proc.stderr.close()
return proc.stdin, proc.stdout
######
......@@ -36,7 +50,7 @@ def gpg(command, args = None):
SSH = '/usr/bin/ssh'
SSH_HOST = 'localhost'
REMOTE_COMMAND = ['/home/nicolasd/cranspasswords-server.py']
REMOTE_COMMAND = ['/home/dstan/crans/cranspasswords/cranspasswords-server.py']
def ssh(command, arg = None):
"""Lance ssh avec les arguments donnés. Renvoie son entrée
......@@ -106,7 +120,9 @@ def check_keys():
for mail, key in keys.values():
if key:
_, stdout = gpg("fingerprint", [key])
if "<%s>" % mail.lower() not in stdout.read().lower():
if DEBUG: print "Checking %s" % mail
if str("<%s>" % mail.lower()) not in stdout.read().lower():
if DEBUG: print "-->Fail on %s" % mail
break
else:
return True
......@@ -133,7 +149,12 @@ def encrypt(roles, contents):
stdin, stdout = gpg("encrypt", email_recipients)
stdin.write(contents)
stdin.close()
return stdout.read()
out = stdout.read()
if out == '':
if DEBUG: print "Échec de chiffrement"
return None
else:
return out
def decrypt(contents):
"""Déchiffre le contenu"""
......@@ -146,11 +167,136 @@ def put_password(name, roles, contents):
"""Dépose le mot de passe après l'avoir chiffré pour les
destinataires donnés"""
enc_pwd = encrypt(roles, contents)
return put_file(name, roles, enc_pwd)
if enc_pwd <> None:
return put_file(name, roles, enc_pwd)
else:
return False
def get_password(name):
"""Récupère le mot de passe donné par name"""
remotefile = get_file(name)
return decrypt(remotefile['contents'])
## Interface
def usage():
print """Cranspasswords 2 Usage:
cranspasswords [options] [<filename>]
cranspasswords <filename> Télécharge le fichier
cranspasswords Mode interactif
Options:
--view Télécharge le fichier
# --upload Upload un nouveau fichier depuis stdin
--edit Lance $EDITOR sur le fichier
# --roles=<role1>,<role2>… Définit les rôles
# --roles+=<role> Ajoute un rôle
# --roles-=<role> Supprime un rôle
# --edit-roles Lance $EDITOR sur les rôles
# --rm Supprime le fichier
--update-keys Mets à jour les clés
--check-keys Vérifie les clés
-l, --list Liste les fichiers disponibles
--list-roles Liste des rôles disponibles
-c, --clipboard mot de passe en presse papier"""
def editor(texte):
""" Lance $EDITOR sur texte"""
f = tempfile.NamedTemporaryFile()
atexit.register(f.close)
f.write(texte)
f.flush()
proc = subprocess.Popen(os.getenv('EDITOR') + ' ' + f.name,shell=True)
os.waitpid(proc.pid,0)
f.seek(0)
ntexte = f.read()
f.close()
return texte <> ntexte and ntexte or None
def show_files():
print """Liste des fichiers disponibles"""
for fname in all_files():
print " * " + fname
def show_roles():
print """Liste des roles disponibles"""
for role in all_roles().keys():
if role.endswith('-w'): continue
print " * " + role
def clipboard(texte):
proc =subprocess.Popen(['xclip','-selection','clipboard'],\
stdin=subprocess.PIPE,stdout=sys.stdout,stderr=sys.stderr)
proc.stdin.write(texte)
proc.stdin.close()
print "[Le mot de passe a été mis dans le presse papier]"
def show_file(fname):
value = get_file(fname)
if value == False:
print "Fichier introuvable"; return
print "Fichier %s:" % fname
(sin,sout) = gpg('decrypt')
sin.write(value['contents'])
sin.close()
texte = sout.read()
if CLIPBOARD: # Ça ne va pas plaire à tout le monde
lines = texte.split('\n')
if len(lines) == 2:
clipboard(lines[0])
else:
for line in lines:
if line.startswith('pass:'):
clipboard(line[5:].strip(' \t\r\n'))
else:
print line
else:
print texte
print "-----"
print "Visible par: %s" % ','.join(value['roles'])
# Todo: some clipboard facility
def edit_file(fname):
value = get_file(fname)
if value == False:
print "Fichier introuvable"; return
(sin,sout) = gpg('decrypt')
sin.write(value['contents'])
sin.close()
texte = sout.read()
ntexte = editor(texte)
if ntexte == None:
print "Pas de modifications effectuées"
else:
if put_password(fname,value['roles'],ntexte):
print "Modifications enregistrées"
else:
print "Erreur lors de l'enregistrement (avez-vous les droits suffisants ?)"
if __name__ == "__main__":
argv = sys.argv[1:]
if '-c' in argv or '--clipboard' in argv:
CLIPBOARD=True
action = show_file
if '--edit' in argv:
action = edit_file
if '-v' in argv: #Verbose !
DEBUG = True
for arg in argv:
if arg in ['--list','-l']:
show_files()
elif not arg.startswith('-'):
action(arg)
elif arg == '--check-keys':
print check_keys() and "Base de clés ok" or "Erreurs dans la base"
elif arg == '--update-keys':
print update_keys()
elif arg == '--list-roles':
show_roles()
elif arg in ['-c','--clipboard','--view','--edit','-v']:
pass
else:
usage()
break
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment