240 lines
6.4 KiB
Python
Executable file
240 lines
6.4 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# -*- encoding: utf-8 -*-
|
|
"""cranspasswords-server.py: Serveur pour cranspasswords"""
|
|
|
|
MYDIR = '/root/cranspasswords/'
|
|
STORE = MYDIR+'db/'
|
|
|
|
import glob
|
|
import os
|
|
import pwd
|
|
import sys
|
|
import json
|
|
import smtplib
|
|
import datetime
|
|
from email.mime.text import MIMEText
|
|
from email.mime.multipart import MIMEMultipart
|
|
|
|
MYUID = pwd.getpwuid(os.getuid())[0]
|
|
if MYUID == 'root':
|
|
MYUID = os.environ['SUDO_USER']
|
|
|
|
CRANSP_MAIL = "root@crans.org"
|
|
DEST_MAIL = "root@crans.org"
|
|
|
|
KEYS = {
|
|
"aza-vallina": ("Damien.Aza-Vallina@crans.org", None),
|
|
"dandrimont": ("nicolas.dandrimont@crans.org", "66475AAF"),
|
|
"blockelet": ("blockelet@crans.org", "AF087A52"),
|
|
"chambart": ("pierre.chambart@crans.org", "F2530FCE"),
|
|
"dimino": ("jdimino@dptinfo.ens-cachan.fr", "2127F85A"),
|
|
"durand-gasselin": ("adg@crans.org", "8E96ACDA"),
|
|
"glondu": ("Stephane.Glondu@crans.org", "49881AD3"),
|
|
"huber": ("olivier.huber@crans.org", "E0DCF376"),
|
|
"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"),
|
|
"samir": ("samir@crans.org", "41C2B76B"),
|
|
"boilard": ("boilard@crans.org", "C39EB6F4"),
|
|
"cauderlier": ("cauderlier@crans.org",None), #Méchant pas beau
|
|
"maioli": ("maioli@crans.org",None), #Bis (maybe 9E5026E8)
|
|
"legallic": ("legallic@crans.org", "3784CFC3"),
|
|
}
|
|
|
|
RTC=[
|
|
"iffrig"
|
|
]
|
|
NOUNOUS=RTC+[
|
|
"blockelet",
|
|
"becue",
|
|
"dstan",
|
|
"chambart",
|
|
"dimino",
|
|
"durand-gasselin",
|
|
"glondu",
|
|
"huber",
|
|
"lagorce",
|
|
"parret-freaud",
|
|
"cauderlier",
|
|
"maioli",
|
|
"samir",
|
|
"boilard",
|
|
"legallic",
|
|
]
|
|
|
|
CA=[]
|
|
|
|
ROLES = {
|
|
"ca": CA,
|
|
"ca-w": CA,
|
|
"nounous": NOUNOUS,
|
|
"nounous-w": NOUNOUS,
|
|
}
|
|
|
|
|
|
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 mode == 'w': role+='-w'
|
|
if ROLES.has_key(role) and MYUID in ROLES[role]:
|
|
return True
|
|
return False
|
|
|
|
def getpath(filename,backup=False):
|
|
"""Récupère le chemin du fichier `filename'"""
|
|
return os.path.join(STORE, '%s.%s' % (filename,'bak' if backup else 'json'))
|
|
|
|
def writefile(filename, contents):
|
|
"""Écrit le fichier de manière sécure"""
|
|
os.umask(0077)
|
|
f = open(filename, 'w')
|
|
f.write(contents)
|
|
f.close()
|
|
|
|
def listroles():
|
|
"""Liste des roles existant et de leurs membres"""
|
|
return ROLES
|
|
|
|
def listkeys():
|
|
"""Liste les uid et les clés correspondantes"""
|
|
return KEYS
|
|
|
|
def listfiles():
|
|
"""Liste les fichiers dans l'espace de stockage, et les roles qui peuvent y accéder"""
|
|
os.chdir(STORE)
|
|
|
|
filenames = glob.glob('*.json')
|
|
|
|
files = {}
|
|
|
|
for filename in filenames:
|
|
file_dict = json.loads(open(filename).read())
|
|
files[filename[:-5]] = file_dict["roles"]
|
|
|
|
return files
|
|
|
|
def getfile(filename):
|
|
"""Récupère le fichier `filename'"""
|
|
|
|
filepath = getpath(filename)
|
|
try:
|
|
obj = json.loads(open(filepath).read())
|
|
if not validate(obj['roles']):
|
|
return False
|
|
return obj
|
|
except IOError:
|
|
return False
|
|
|
|
|
|
def putfile(filename):
|
|
"""Écrit le fichier `filename' avec les données reçues sur stdin."""
|
|
|
|
filepath = getpath(filename)
|
|
|
|
stdin = sys.stdin.read()
|
|
parsed_stdin = json.loads(stdin)
|
|
|
|
try:
|
|
roles = parsed_stdin['roles']
|
|
contents = parsed_stdin['contents']
|
|
except KeyError:
|
|
return False
|
|
|
|
try:
|
|
old = getfile(filename)
|
|
oldroles = old['roles']
|
|
except TypeError:
|
|
old = "[Création du fichier]"
|
|
pass
|
|
else:
|
|
if not validate(oldroles,'w'):
|
|
return False
|
|
|
|
notification("Modification de %s" % filename,\
|
|
"Le fichier %s a été modifié par %s." %\
|
|
(filename,MYUID),filename,old)
|
|
|
|
|
|
writefile(filepath, json.dumps({'roles': roles, 'contents': contents}))
|
|
return True
|
|
|
|
def rmfile(filename):
|
|
"""Supprime le fichier filename après avoir vérifié les droits sur le fichier"""
|
|
try:
|
|
old = getfile(filename)
|
|
roles = old['roles']
|
|
except TypeError:
|
|
return True
|
|
else:
|
|
if validate(roles,'w'):
|
|
notification("Suppression de %s" % filename,\
|
|
"Le fichier %s a été supprimé par %s." %\
|
|
(filename,MYUID),filename,old)
|
|
os.remove(getpath(filename))
|
|
else:
|
|
return False
|
|
return True
|
|
|
|
def notification(subject,corps,fname,old):
|
|
back = open(getpath(fname,True),'a')
|
|
back.write(json.dumps(old))
|
|
back.write('\n')
|
|
back.write('* %s: %s\n' % (str(datetime.datetime.now()),corps))
|
|
back.close()
|
|
|
|
# Puis envoi du message
|
|
conn = smtplib.SMTP('localhost')
|
|
frommail = CRANSP_MAIL
|
|
tomail = DEST_MAIL
|
|
msg = MIMEMultipart(_charset="utf-8")
|
|
msg['Subject'] = subject
|
|
# me == the sender's email address
|
|
# family = the list of all recipients' email addresses
|
|
msg['From'] = "cranspasswords <%s>" % CRANSP_MAIL
|
|
msg['To'] = DEST_MAIL
|
|
msg.preamble = "cranspasswords report"
|
|
info = MIMEText(corps +
|
|
"\nLa version précédente a été sauvegardée." +
|
|
#"\nCi-joint l'ancien fichier." +
|
|
"\n\n-- \nCranspasswords.py",_charset="utf-8")
|
|
msg.attach(info)
|
|
#old = MIMEText(old)
|
|
#old.add_header('Content-Disposition', 'attachment', filename=fname)
|
|
#msg.attach(str(old))
|
|
conn.sendmail(frommail,tomail,msg.as_string())
|
|
conn.quit()
|
|
|
|
if __name__ == "__main__":
|
|
argv = sys.argv[1:]
|
|
if len(argv) not in [1, 2]:
|
|
sys.exit(1)
|
|
command = argv[0]
|
|
filename = None
|
|
try:
|
|
filename = argv[1]
|
|
except IndexError:
|
|
pass
|
|
|
|
if command == "listroles":
|
|
print json.dumps(listroles())
|
|
elif command == "listkeys":
|
|
print json.dumps(listkeys())
|
|
elif command == "listfiles":
|
|
print json.dumps(listfiles())
|
|
else:
|
|
if not filename:
|
|
sys.exit(1)
|
|
if command == "getfile":
|
|
print json.dumps(getfile(filename))
|
|
elif command == "putfile":
|
|
print json.dumps(putfile(filename))
|
|
elif command == "rmfile":
|
|
print json.dumps(rmfile(filename))
|
|
else:
|
|
sys.exit(1)
|
|
|