Ménage dans la partie wifi
A priori, le dossier wifi n'a pas de dépendance (enfin, un grep "bornes" -r | grep import ne m'a rient donné). wifiweb, n'en parlons pas.
This commit is contained in:
parent
574a2aadf0
commit
21fc3e42d6
11 changed files with 1 additions and 0 deletions
29
archive/wifi/addip.c
Normal file
29
archive/wifi/addip.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* A compiler avec gcc -Wall -ansi -static addip.c -o /var/www/cgi-bin/addip.cgi */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main() {
|
||||
FILE *fd;
|
||||
char *ip;
|
||||
|
||||
if ((fd = fopen("/hotspot.socket", "a")) == NULL)
|
||||
goto erreur;
|
||||
|
||||
if ((ip = getenv("REMOTE_ADDR")) == NULL)
|
||||
goto erreur;
|
||||
|
||||
fprintf(fd, "%s\n", ip);
|
||||
fflush(fd);
|
||||
fclose(fd);
|
||||
|
||||
printf("Location: https://wifi.crans.org/wiki/WiFi(2f)PagesStatiques(2f)PortailCaptif(2f)AuthOk.html\r\n");
|
||||
printf("\r\n");
|
||||
return 0;
|
||||
|
||||
erreur:
|
||||
printf("Location: https://wifi.crans.org/wiki/WiFi(2f)PagesStatiques(2f)PortailCaptif(2f)AuthErreur.html\r\n");
|
||||
printf("\r\n");
|
||||
return 0;
|
||||
}
|
241
archive/wifi/bornes.py
Executable file
241
archive/wifi/bornes.py
Executable file
|
@ -0,0 +1,241 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# uname_bornes.py
|
||||
# ---------------
|
||||
# Copyright : (c) 2009, Jeremie Dimino <jeremie@dimino.org>
|
||||
# Licence : BSD3
|
||||
|
||||
"""Script qui fait un uname sur toute les bornes à la fois.
|
||||
|
||||
La sortie est la sortie de `uname -v` sur chaque borne."""
|
||||
|
||||
import sys, os, commands, re, time
|
||||
from subprocess import Popen, PIPE
|
||||
from optparse import OptionParser
|
||||
|
||||
LOG = "/var/log/wifi/wifi.log"
|
||||
DELTA = 60*60
|
||||
|
||||
def bornes():
|
||||
"""Renvoie la liste des bornes
|
||||
|
||||
Moyen rapide, mais peut-être un peu crade pour récupérer la liste des bornes:
|
||||
on regarde les machines présentes dans 138.231.148.1/24"""
|
||||
names = []
|
||||
for line in commands.getoutput("host -l wifi.crans.org sable.crans.org").splitlines()[5:]:
|
||||
# Chaque ligne est de la forme:
|
||||
# "truc.wifi.crans.org has address 138.231.148.42"
|
||||
fields = line.split()
|
||||
name = fields[0].split(".")[0]
|
||||
ip = fields[3]
|
||||
network = ip.rsplit(".", 1)[0]
|
||||
# On ne prend que les machines du réseau 138.231.148.0/24, à part
|
||||
# ragnarok:
|
||||
if network == "138.231.148" and ip != "138.231.148.1":
|
||||
names.append(name)
|
||||
return names
|
||||
|
||||
def ssh_exec(host, cmd):
|
||||
"""Execute une commande en ssh sur une machine et renvoie le résultat"""
|
||||
p = Popen("ssh -T -x -o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=no -l root -i /usr/scripts/gestion/clef-wifi %(host)s %(cmd)s" % locals(), shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
|
||||
p.stdin.close()
|
||||
p.stderr.close()
|
||||
return p.stdout
|
||||
|
||||
def bornes_canal():
|
||||
names = bornes()
|
||||
outputs = {}
|
||||
for name in names:
|
||||
outputs[name] = ssh_exec(name+".wifi", '/usr/sbin/iwlist wlan0 channel')
|
||||
|
||||
while True:
|
||||
try: os.wait()
|
||||
except OSError: break
|
||||
|
||||
# On lit tout les résultats:
|
||||
results = {}
|
||||
for name, output in outputs.iteritems():
|
||||
results[name] = None
|
||||
for l in output.readlines():
|
||||
m = re.match('\s*Current(.*)\\(Channel ([0-9]*)\\)',l)
|
||||
if m:
|
||||
results[name] = m.group(2)
|
||||
break
|
||||
output.close()
|
||||
return results
|
||||
|
||||
|
||||
def bornes_clients():
|
||||
names = bornes()
|
||||
outputs = {}
|
||||
for name in names:
|
||||
outputs[name] = ssh_exec(name+".wifi", '/usr/sbin/iw dev wlan0 station dump')
|
||||
|
||||
# count = 0
|
||||
# total = len(names)
|
||||
while True:
|
||||
try: os.wait()
|
||||
except OSError: break
|
||||
|
||||
# On lit tout les résultats:
|
||||
results = {}
|
||||
for name, output in outputs.iteritems():
|
||||
results[name] = str(len([1 for line in output.readlines() if line.startswith('Station')]))
|
||||
output.close()
|
||||
return results
|
||||
|
||||
def bornes_uptime():
|
||||
names = bornes()
|
||||
outputs = {}
|
||||
for name in names:
|
||||
outputs[name] = ssh_exec(name+".wifi", 'cat /proc/uptime')
|
||||
|
||||
count = 0
|
||||
total = len(names)
|
||||
while count < total:
|
||||
try: os.wait()
|
||||
except OSError: break
|
||||
|
||||
# On lit tout les résultats:
|
||||
results = {}
|
||||
for name, output in outputs.iteritems():
|
||||
uptime = output.read().strip()
|
||||
if uptime:
|
||||
results[name] = str(float(uptime.split()[1]) / (24*3600))
|
||||
else:
|
||||
results[name] = '0'
|
||||
output.close()
|
||||
return results
|
||||
|
||||
def munin(config, cmd=None, process=(lambda x: x), results=None, buckets=None, stack=None):
|
||||
"""plugin munin"""
|
||||
|
||||
if 'autoconf' in sys.argv:
|
||||
print 'yes'
|
||||
sys.exit(0)
|
||||
|
||||
names = bornes()
|
||||
|
||||
if 'config' in sys.argv:
|
||||
print config
|
||||
print "graph_category wifi"
|
||||
if buckets:
|
||||
for i, (val, lbl) in enumerate(buckets.items()):
|
||||
print "%s.label %s" % (lbl, val)
|
||||
if stack:
|
||||
if i == 0: print "%s.draw %s" % (lbl, stack)
|
||||
else: print "%s.draw STACK" % lbl
|
||||
else:
|
||||
for i, borne in enumerate(names):
|
||||
print "%s.label %s" % (borne, borne)
|
||||
if stack:
|
||||
if i == 0: print "%s.draw %s" % (borne, stack)
|
||||
else: print "%s.draw STACK" % borne
|
||||
sys.exit(0)
|
||||
|
||||
if not results:
|
||||
res = results = {}
|
||||
for name in names: res[name] = ssh_exec(name+".wifi", cmd)
|
||||
for name in names: results[name] = res[name].read()
|
||||
|
||||
if buckets:
|
||||
bins = {}
|
||||
for (lbl, val) in buckets.iteritems(): bins[val] = 0
|
||||
for name, res in results.iteritems():
|
||||
try:
|
||||
value = process(res).split('\n', 1)[0].strip()
|
||||
if buckets: bins[buckets[value]] += 1
|
||||
else: print '%s.value %s' % (name, value)
|
||||
except: pass
|
||||
|
||||
if buckets:
|
||||
for name, res in bins.iteritems():
|
||||
print '%s.value %s' % (name, res)
|
||||
|
||||
|
||||
def main():
|
||||
parser = OptionParser(usage=usage)
|
||||
|
||||
parser.add_option('-v', '--uname', help=u"renvoie le uname -v",
|
||||
action='store_const', const='uname -v', dest='cmd', default='uname -v')
|
||||
parser.add_option('-u', '--uptime', help=u"renvoie l'uptime",
|
||||
action='store_const', const='uptime', dest='cmd')
|
||||
parser.add_option('-w', '--mac-wifi',
|
||||
help=u"renvoie l'addresse MAC de l'access point",
|
||||
action='store_const', dest='cmd',
|
||||
const="iwconfig wl0 | sed -n 's/^.*00:/00:/p'")
|
||||
parser.add_option('-c', '--custom', help=u'exécute une commande custom',
|
||||
action='store', dest='cmd')
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
names = bornes()
|
||||
outputs = {}
|
||||
for name in names:
|
||||
outputs[name] = ssh_exec(name+".wifi", commands.mkarg(options.cmd))
|
||||
|
||||
# On attend que tous les fils qu'on a lancé terminent, avec une petite
|
||||
# animation si la sortie est un terminal:
|
||||
count = 0
|
||||
total = len(names)
|
||||
show_anim = sys.stderr.isatty()
|
||||
message = "Réception des résultats: %d/%d"
|
||||
if show_anim: sys.stderr.write(message % (count, total))
|
||||
while count < total:
|
||||
try: os.wait()
|
||||
except OSError: break
|
||||
count += 1
|
||||
if show_anim: sys.stderr.write("\r" + message % (count, total))
|
||||
if show_anim: sys.stderr.write("\n")
|
||||
|
||||
# On lit tout les résultats:
|
||||
results = {}
|
||||
for name, output in outputs.iteritems():
|
||||
results[name] = output.read().strip()
|
||||
output.close()
|
||||
|
||||
results = results.items()
|
||||
results.sort(key=lambda x: x[0])
|
||||
|
||||
for name, result in results:
|
||||
if not result:
|
||||
print "%-15s failure" % (name + ":")
|
||||
|
||||
for name, result in results:
|
||||
if result:
|
||||
print "%-15s %s" % (name + ":", result)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
usage = u"""usage: %prog [OPTION]
|
||||
Récupère la liste des bornes et récupère le résultat d'une commande sur
|
||||
toutes les bornes"""
|
||||
prog = os.path.basename(sys.argv[0])
|
||||
if len(prog.split('_', 1)) > 1:
|
||||
plugin = prog.split('_', 1)[0]
|
||||
if plugin == 'uptime':
|
||||
config = """graph_title Uptime Bornes
|
||||
graph_args --base 1000 --logarithmic -l 0.5 -u 500 -r
|
||||
graph_vlabel uptime in days"""
|
||||
def process(uptime):
|
||||
if uptime: return str(float (uptime.split()[1]) / (24 * 3600))
|
||||
else: return None
|
||||
munin(config, cmd = 'cat /proc/uptime', process=process)
|
||||
elif plugin == 'clients':
|
||||
config = """graph_title Clients connectés
|
||||
graph_args --base 1000 -l 0
|
||||
graph_vlabel Clients connectés"""
|
||||
munin(config, results=bornes_clients(), stack="AREA")
|
||||
elif plugin == 'canal':
|
||||
config = """graph_title Canaux utilisés
|
||||
graph_args --base 1000 -l 0"""
|
||||
buckets = {'1': 'un', '2': 'deux', '3': 'trois', '4': 'quatre',
|
||||
'5': 'cinq', '6': 'six', '7': 'sept', '8': 'huit',
|
||||
'9': 'neuf', '10': 'dix', '11': 'onze', '12': 'douze',
|
||||
'13': 'treize', '14': 'quatorze', '0': 'echec' }
|
||||
munin(config, results=bornes_canal(), buckets= buckets, stack="AREA")
|
||||
else: raise NotImplementedError
|
||||
|
||||
else:
|
||||
main()
|
148
archive/wifi/hotspot.py
Normal file
148
archive/wifi/hotspot.py
Normal file
|
@ -0,0 +1,148 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- encoding: iso-8859-15 -*-
|
||||
|
||||
# Gestion du portail captif :
|
||||
# - lecture d'une socket pour les IP à ajouter
|
||||
# - lecture du fichier de lease DHCP pour les expirer
|
||||
|
||||
import os
|
||||
from popen2 import Popen4
|
||||
import sys
|
||||
import time
|
||||
import re
|
||||
from syslog import openlog, syslog, LOG_ERR, LOG_LOCAL4, LOG_INFO, LOG_LOCAL3, LOG_PERROR, LOG_PID, LOG_CRIT
|
||||
from lease import Leases
|
||||
from select import select
|
||||
|
||||
class Server:
|
||||
"""Serveur (sur socket) gérant le hotspot"""
|
||||
|
||||
def __init__(self, socket):
|
||||
"""Initialise le serveur.
|
||||
|
||||
Il écoutera sur le pipe nommé `socket'."""
|
||||
# syslog
|
||||
openlog("hotspot.py", LOG_PERROR | LOG_PID)
|
||||
# Initialisation de la socket
|
||||
self._dontclean = False
|
||||
try:
|
||||
os.unlink(socket)
|
||||
except:
|
||||
pass
|
||||
os.mkfifo(socket, 0600)
|
||||
os.chown(socket, 67, -1)
|
||||
self.socket = file(socket, "a+")
|
||||
|
||||
def execute(self,cmd):
|
||||
"""Exécute une commande.
|
||||
|
||||
Gère les erreurs par log dans syslog."""
|
||||
p = Popen4(cmd)
|
||||
p.tochild.close()
|
||||
out = p.fromchild.read()
|
||||
p.fromchild.close()
|
||||
exit = os.WEXITSTATUS(p.wait())
|
||||
if exit:
|
||||
# Une erreur a eu lieu
|
||||
syslog(LOG_ERR | LOG_LOCAL4,
|
||||
"Error %d executing `%s' : %s" % (exit, cmd.strip(), out.strip()))
|
||||
else:
|
||||
return out
|
||||
|
||||
def add_ip(self,ip):
|
||||
"""Ajout d'une IP au firewall"""
|
||||
cmd = "pfctl -t clients_hotspot_autorises -Tadd %s" % ip
|
||||
if self.execute(cmd):
|
||||
syslog(LOG_INFO | LOG_LOCAL4, "Nouveau client hotspots: %s" % ip)
|
||||
|
||||
|
||||
def del_ip(self,ip):
|
||||
"""Retire une règle du firewall"""
|
||||
cmd = "pfctl -t clients_hotspot_autorises -Tdelete %s" % ip
|
||||
if self.execute(cmd):
|
||||
syslog(LOG_INFO | LOG_LOCAL4, "Suppression du client: %s" % ip)
|
||||
|
||||
def list_ips(self):
|
||||
"""Liste les IP actuellement dans le firewall"""
|
||||
cmd = "pfctl -t clients_hotspot_autorises -Tshow"
|
||||
ips = self.execute(cmd)
|
||||
if not ips:
|
||||
return []
|
||||
return filter(lambda y: y.strip() != '',
|
||||
map(lambda x: x.strip(), ips.split("\n")))
|
||||
|
||||
def prune_ips(self):
|
||||
"""Vire les IP qui ne sont plus utilisées"""
|
||||
l = Leases().leases
|
||||
deleted = False
|
||||
for ip in self.list_ips():
|
||||
match = filter(lambda x: x.ip == ip, l)
|
||||
if not match:
|
||||
# Plus de bail du tout
|
||||
self.del_ip(ip)
|
||||
deleted = True
|
||||
else:
|
||||
# On vérifie si le bail n'a pas expiré depuis plus de une minute
|
||||
if match[0].end < time.gmtime(time.time()-60):
|
||||
self.del_ip(ip)
|
||||
deleted=True
|
||||
syslog(LOG_INFO | LOG_LOCAL3, "Clients hotspots: %s" % (", ".join(self.list_ips()) or "aucun"))
|
||||
|
||||
def daemonize(self):
|
||||
"""Passe en arrière plan"""
|
||||
# Fork
|
||||
if os.fork() > 0:
|
||||
self._dontclean = True
|
||||
sys.exit(0)
|
||||
# Bon répertoire
|
||||
os.chdir("/")
|
||||
# Masque indépendant de l'utilisateur
|
||||
os.umask(022)
|
||||
# Chef de file
|
||||
os.setsid()
|
||||
# Second fork pour avoir son groupe
|
||||
if os.fork() > 0:
|
||||
self._dontclean = True
|
||||
sys.exit(0)
|
||||
# Redirection des E/S
|
||||
si = file('/dev/null', 'r')
|
||||
so = file('/dev/null', 'a+')
|
||||
se = file('/dev/null', 'a+', 0)
|
||||
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
def start(self):
|
||||
"""Boucle principale"""
|
||||
syslog(LOG_INFO | LOG_LOCAL4, "Demarrage du demon hotspot")
|
||||
s = self.socket.fileno()
|
||||
while True:
|
||||
# On attend du monde sur la socket
|
||||
result = select([s],[],[],60)[0]
|
||||
if result:
|
||||
# On a quelqu'un, on lit une ligne
|
||||
syslog(LOG_INFO | LOG_LOCAL4, "Nouvelle requete")
|
||||
ip = self.socket.readline().strip()
|
||||
syslog(LOG_INFO | LOG_LOCAL4, "Nouvelle requete pour l'IP : %s" % ip)
|
||||
if re.match("^10\.231.*", ip):
|
||||
self.add_ip(ip)
|
||||
# Dans tous les cas, on vire les IP inutiles
|
||||
self.prune_ips()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
s = Server("/var/www/hotspot.socket")
|
||||
s.daemonize()
|
||||
while True:
|
||||
try:
|
||||
s.start()
|
||||
except:
|
||||
import traceback
|
||||
from cStringIO import StringIO
|
||||
ss = StringIO()
|
||||
sys.stderr = ss
|
||||
traceback.print_exc()
|
||||
sys.stderr = sys.__stderr__
|
||||
syslog(LOG_CRIT | LOG_LOCAL4, "Erreur importante :\n%s" % ss.getvalue())
|
||||
time.sleep(60) # Pour ne pas flooder...
|
||||
|
65
archive/wifi/lease.py
Normal file
65
archive/wifi/lease.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- encoding: iso-8859-15 -*-
|
||||
|
||||
# Gestion en lecture d'un fichier lease (issu du DHCPD d'Open)
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
class Lease:
|
||||
"""Classe représentant un bail (lease)."""
|
||||
|
||||
def __init__(self, texte):
|
||||
"""Instanciation d'un bail
|
||||
|
||||
L'instanciation se fait en fournissant `texte' qui est la
|
||||
forme textuelle du bail qui se trouve dans
|
||||
/var/db/dhcpd.leases de la forme :
|
||||
|
||||
lease 10.231.149.89 {
|
||||
starts 3 2005/11/09 07:58:52;
|
||||
ends 3 2005/11/09 08:13:52;
|
||||
hardware ethernet 00:0c:f1:37:54:2c;
|
||||
uid 01:00:0c:f1:37:54:2c;
|
||||
client-hostname "FCDVIRELY";
|
||||
}
|
||||
"""
|
||||
mo = re.search("\\blease ([0-9\\.]*) \\{", texte)
|
||||
if not mo:
|
||||
raise ValueError, u"Pas de bail trouvé"
|
||||
self.ip = mo.group(1)
|
||||
|
||||
mo = re.search("\\bstarts [0-7] ([0-9/]* [0-9:]*);", texte)
|
||||
if not mo:
|
||||
raise ValueError, u"Pas de date de début de bail"
|
||||
self.start = time.strptime(mo.group(1), "%Y/%m/%d %H:%M:%S")
|
||||
|
||||
mo = re.search("\\bends [0-7] ([0-9/]* [0-9:]*);", texte)
|
||||
if not mo:
|
||||
raise ValueError, u"Pas de date de fin de bail"
|
||||
self.end = time.strptime(mo.group(1), "%Y/%m/%d %H:%M:%S")
|
||||
|
||||
mo = re.search("\\bhardware ethernet ([0-9a-f:]*);", texte)
|
||||
if not mo:
|
||||
raise ValueError, u"Pas d'adresse Ethernet pour le bail %s" % self.ip
|
||||
self.mac = mo.group(1)
|
||||
|
||||
# On n'est pas intéressé par le reste
|
||||
|
||||
class Leases:
|
||||
"""Classe représentant un ensemble de bails."""
|
||||
|
||||
def __init__(self, fichier="/var/db/dhcpd.leases"):
|
||||
"""Instanciation à partir du fichier de leases."""
|
||||
self.leases = []
|
||||
# Méthode rapide :
|
||||
for lease in " ".join(file(fichier).readlines()).split("}")[:-1]:
|
||||
try:
|
||||
nouveau = Lease(lease)
|
||||
# On enleve les anciens
|
||||
self.leases = filter(lambda x: x.ip != nouveau.ip, self.leases)
|
||||
# On rajoute le nouveau
|
||||
self.leases.append(nouveau)
|
||||
except ValueError:
|
||||
# Certains baux peuvent ne pas avoir d'adresse MAC
|
||||
pass
|
100
archive/wifi/status.py
Normal file
100
archive/wifi/status.py
Normal file
|
@ -0,0 +1,100 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: iso-8859-15 -*-
|
||||
|
||||
# Génération d'un fichier XML indiquant le status des bornes
|
||||
|
||||
import sys, os, time, optparse
|
||||
sys.path.append("/usr/scripts/gestion")
|
||||
sys.path.append("/usr/scripts/wifi")
|
||||
|
||||
### parsing
|
||||
parser = optparse.OptionParser(usage="usage: %prog [-o FILE]")
|
||||
parser.add_option('-o', '--output', help=u"outputs to FILE",
|
||||
metavar='FILE', dest="filename")
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
from bornes import bornes_canal, bornes_clients, bornes_uptime
|
||||
|
||||
from ldap_crans import crans_ldap
|
||||
l = crans_ldap()
|
||||
|
||||
import xml.dom.minidom
|
||||
|
||||
# création objet xml
|
||||
status=xml.dom.minidom.Document()
|
||||
|
||||
xml_bornes=status.createElement(u"bornes")
|
||||
status.appendChild(xml_bornes)
|
||||
xml_bornes.setAttribute(u"date",time.strftime("%c"))
|
||||
|
||||
# On récupère l'ensemble des bornes
|
||||
bornes = l.search('host=*.wifi.crans.org&canal=*')['borneWifi']
|
||||
bornes.sort(cmp=(lambda x, y: cmp(x.nom(), y.nom())))
|
||||
|
||||
canaux = bornes_canal()
|
||||
clients = bornes_clients()
|
||||
uptimes = bornes_uptime()
|
||||
|
||||
for b in bornes:
|
||||
infos = filter(lambda x: not x.startswith("<"), b.info())
|
||||
if not infos or b.nom().split('.')[0]=="non-configure":
|
||||
# Rien à propos de cette borne...
|
||||
continue
|
||||
|
||||
# Est-ce un hotspot ?
|
||||
hotspot = b.hotspot() and 1 or 0
|
||||
# Est-ce que la borne est up ?
|
||||
if os.system("/usr/bin/fping -q %s 2> /dev/null" % b.nom()) == 0:
|
||||
up = 1
|
||||
else:
|
||||
up = 0
|
||||
# Quel nom ?
|
||||
nom = b.nom().split(".")[0]
|
||||
xml_borne=status.createElement(u"borne")
|
||||
xml_borne.setAttribute(u"nom",nom)
|
||||
xml_borne.setAttribute(u"hotspot",unicode(hotspot))
|
||||
xml_borne.setAttribute(u"up",unicode(up))
|
||||
|
||||
xml_desc=status.createElement(u"description")
|
||||
xml_desc.appendChild(status.createTextNode(infos[0]))
|
||||
#xml_desc.appendChild(status.createTextNode(u"Description pas compatible unicode/ascii"))
|
||||
xml_borne.appendChild(xml_desc)
|
||||
xml_mac=status.createElement(u"mac")
|
||||
xml_mac.appendChild(status.createTextNode(b.mac2()))
|
||||
xml_borne.appendChild(xml_mac)
|
||||
|
||||
# Certains résultats (ragnarok) n'ont pas tous les champs.
|
||||
if (canaux.has_key(nom)):
|
||||
xml_canal=status.createElement(u"canal")
|
||||
try: canal = unicode(int(canaux[nom]))
|
||||
except TypeError: canal = u'Inconnu'
|
||||
xml_canal.appendChild(status.createTextNode(canal))
|
||||
xml_borne.appendChild(xml_canal)
|
||||
|
||||
if (clients.has_key(nom)):
|
||||
xml_clients=status.createElement(u"clients")
|
||||
try: client = unicode(int(clients[nom]))
|
||||
except TypeError: client = u'Inconnu'
|
||||
xml_clients.appendChild(status.createTextNode(client))
|
||||
xml_borne.appendChild(xml_clients)
|
||||
|
||||
if (uptimes.has_key(nom)):
|
||||
xml_uptime=status.createElement(u"uptime")
|
||||
xml_uptime.appendChild(status.createTextNode(unicode(uptimes[nom])))
|
||||
xml_borne.appendChild(xml_uptime)
|
||||
|
||||
position = b.position()
|
||||
if position:
|
||||
xml_position=status.createElement(u"position")
|
||||
xml_position.setAttribute(u"x",unicode(position[1]))
|
||||
xml_position.setAttribute(u"y",unicode(position[0]))
|
||||
xml_borne.appendChild(xml_position)
|
||||
|
||||
xml_bornes.appendChild(xml_borne)
|
||||
|
||||
if options.filename:
|
||||
f = open(options.filename, 'w')
|
||||
f.write(status.toxml().encode("UTF-8"))
|
||||
f.close()
|
||||
else:
|
||||
print (status.toxml().encode("UTF-8"))
|
26
archive/wifi/wifiweb/adduser.py
Executable file
26
archive/wifi/wifiweb/adduser.py
Executable file
|
@ -0,0 +1,26 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: iso-8859-15 -*-
|
||||
|
||||
# ce script ajoute une ligne à la fin du fichier des utilisateurs
|
||||
# avec le mot de passe déja hashé, il faut ensuite l'integrer au
|
||||
# dictionnaire
|
||||
|
||||
import sha, sys
|
||||
from getpass import getpass
|
||||
|
||||
sys.stdout.write('Nom d\'utilisateur (au format prenom.nom) : ')
|
||||
while True :
|
||||
user = sys.stdin.readline().strip()
|
||||
if user :
|
||||
break
|
||||
|
||||
while True :
|
||||
pass1 = getpass('Mot de passe : ')
|
||||
pass2 = getpass('Retappez le mot de passe : ')
|
||||
if pass1 == pass2 :
|
||||
break
|
||||
print 'Les deux mot de passe ne correpondent pas !'
|
||||
|
||||
f = open('/usr/scripts/wifiweb/utilisateurs.py','a+')
|
||||
f.write('# %s:%s\n' % (user , sha.new(pass1).hexdigest()) )
|
||||
f.close()
|
245
archive/wifi/wifiweb/bornes.py
Normal file
245
archive/wifi/wifiweb/bornes.py
Normal file
|
@ -0,0 +1,245 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: iso-8859-15 -*-
|
||||
|
||||
import cgi, sys, os, sha, time, re
|
||||
from html import html
|
||||
from session import session
|
||||
from utilisateurs import users
|
||||
|
||||
sys.path.append('/usr/scripts/gestion')
|
||||
from ldap_crans import crans_ldap
|
||||
db = crans_ldap()
|
||||
|
||||
######################################################
|
||||
# fontion pour logguer un truc
|
||||
def log (message) :
|
||||
f = open('/var/log/wifiweb.log','a+')
|
||||
f.write( time.strftime('%d/%m/%Y %H:%M:%S',time.localtime(time.time())) + ' ' + message + '\n')
|
||||
f.close()
|
||||
|
||||
######################################################
|
||||
# initialisation des variables
|
||||
|
||||
# initialisation de la page html
|
||||
page = html()
|
||||
page.sendheaderstobrowser()
|
||||
page.titre("Gestion des bornes wifi")
|
||||
|
||||
# récupération des données du formulaire
|
||||
form = cgi.FieldStorage()
|
||||
sid = form.getvalue('sid')
|
||||
action = form.getvalue('action','auth')
|
||||
|
||||
# url
|
||||
try :
|
||||
url = os.environ['HTTP_REFERER']
|
||||
if '?' in url :
|
||||
url = url.split('?')[0]
|
||||
except :
|
||||
url = ''
|
||||
|
||||
# création de la session
|
||||
try :
|
||||
sess = session(sid)
|
||||
except :
|
||||
sess = session()
|
||||
sid = sess.sid
|
||||
|
||||
######################################################
|
||||
# quelques fontions html
|
||||
|
||||
def message (texte, color='black'):
|
||||
return '<font color="%s">%s</font><br>' % (color,texte)
|
||||
|
||||
def message_ok (texte) :
|
||||
return message (texte,'green')
|
||||
|
||||
def message_nok (texte) :
|
||||
return message (texte,'red')
|
||||
|
||||
######################################################
|
||||
# quelques variables html
|
||||
|
||||
def bouton (url='', sid='', action='', caption='') :
|
||||
txt = ''
|
||||
if url :
|
||||
txt += '<form action="%s" method="POST">\n' % url
|
||||
else :
|
||||
txt += '<form method="POST">\n'
|
||||
if sid :
|
||||
txt += '<input type="hidden" name="sid" value="%s">\n' % sid
|
||||
if action :
|
||||
txt += '<input type="hidden" name="action" value="%s">' % action
|
||||
txt += '<input type="submit" value="%s">\n</form>' % caption
|
||||
return txt
|
||||
|
||||
bouton_quitter = bouton (url, sid, 'logout', 'Quitter')
|
||||
bouton_menu = bouton (url, sid, 'index', 'Menu principal')
|
||||
bouton_retour = bouton ('javascript:history.go(-1)', '', '', 'Retour')
|
||||
|
||||
######################################################
|
||||
# authentification
|
||||
|
||||
if action == 'valid-auth' :
|
||||
sess.data['user'] = form.getvalue('user','')
|
||||
sess.data['password'] = sha.new(form.getvalue('password','')).hexdigest()
|
||||
if users.has_key( sess.data['user'] + ':' + sess.data['password'] ) :
|
||||
log(sess.data['user'] + ' s\'est connecté' )
|
||||
action = 'index'
|
||||
|
||||
if not sess.data.has_key('user') or not sess.data.has_key('password') :
|
||||
action = 'auth'
|
||||
|
||||
if action != 'auth' :
|
||||
|
||||
if users.has_key( sess.data['user'] + ':' + sess.data['password'] ) :
|
||||
# droits de l'utilisateur
|
||||
#########################
|
||||
|
||||
# construction de la liste des bornes modifiables
|
||||
bornes_modifiables = []
|
||||
if len(users[ sess.data['user'] + ':' + sess.data['password'] ]) :
|
||||
for lieu in users[ sess.data['user'] + ':' + sess.data['password'] ] :
|
||||
for borne in db.search('canal=*&info=<lieu>%s*' % lieu )['machine'] :
|
||||
nom = borne.nom().encode('iso-8859-15').split('.')[0]
|
||||
if nom not in bornes_modifiables :
|
||||
bornes_modifiables.append(nom)
|
||||
|
||||
else :
|
||||
# erreur d'authentification
|
||||
###########################
|
||||
|
||||
log(sess.data['user'] + ' erreur d\'authentification' )
|
||||
page.add('<font color="red">Erreur d\'authentification !</font><br><br>')
|
||||
action = 'auth'
|
||||
|
||||
######################################################
|
||||
# page : authentification
|
||||
|
||||
if action == 'auth' :
|
||||
page.add("""<center>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="sid" value="%s">
|
||||
<input type="hidden" name="action" value="valid-auth">
|
||||
<table>
|
||||
<tr><td>Utilisateur : </td><td><input type="text" name="user">
|
||||
<tr><td>Mot de passe : </td><td><input type="password" name="password"><br></td></tr>
|
||||
<tr><td collspan="2" align="center"><input type="submit" value="Valider"></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
</center>
|
||||
""" % sid )
|
||||
action = ''
|
||||
|
||||
######################################################
|
||||
# désactivation d'un borne
|
||||
|
||||
if action == 'desactive' and bornes_modifiables :
|
||||
if form.getvalue('borne','') in bornes_modifiables :
|
||||
log(sess.data['user'] + ' a désactivé %s' % form.getvalue('borne','') )
|
||||
page.add('<font color="blue">La borne <b>%s</b> sera désactivée dans quelques instants</font><br><br>' % form.getvalue('borne','') )
|
||||
borne = db.search('host=%s.wifi.crans.org' % form.getvalue('borne',''), 'w' )['machine'][0]
|
||||
if int(borne.puissance()) > 0 :
|
||||
borne.puissance(-int(borne.puissance()))
|
||||
borne.save()
|
||||
action = 'liste-bornes'
|
||||
else :
|
||||
log(sess.data['user'] + ' a tenté de désactiver %s' % form.getvalue('borne','') )
|
||||
action = 'erreur-droits'
|
||||
|
||||
######################################################
|
||||
# activation d'un borne
|
||||
|
||||
if action == 'active' and bornes_modifiables :
|
||||
if form.getvalue('borne','') in bornes_modifiables :
|
||||
log(sess.data['user'] + ' a activé %s' % form.getvalue('borne','') )
|
||||
page.add('<font color="blue">La borne <b>%s</b> sera réactivée dans quelques instants</font><br><br>' % form.getvalue('borne','') )
|
||||
borne = db.search('host=%s.wifi.crans.org' % form.getvalue('borne',''),'w' )['machine'][0]
|
||||
if int(borne.puissance()) < 0 :
|
||||
borne.puissance(int(borne.puissance().replace('-','')))
|
||||
borne.save()
|
||||
action = 'liste-bornes'
|
||||
else :
|
||||
log(sess.data['user'] + ' a tenté d\'activer %s' % form.getvalue('borne','') )
|
||||
page.add('<font color="red">Vous n\'êtes pas authorisé à modifier la borne <b>%s</b></font><br><br>' % form.getvalue('borne','') )
|
||||
action = 'erreur-droits'
|
||||
|
||||
######################################################
|
||||
# page : liste des bornes
|
||||
|
||||
if action == 'liste-bornes' and bornes_modifiables :
|
||||
page.sous_titre('Liste des bornes')
|
||||
|
||||
for b in bornes_modifiables :
|
||||
try :
|
||||
borne = db.search('host=%s.wifi.crans.org' % b)['machine'][0]
|
||||
except :
|
||||
log('borne non existante : %s' % b)
|
||||
continue
|
||||
|
||||
# formulaire
|
||||
page.add('<form method=\"POST\">')
|
||||
page.add('<input type="hidden" name="sid" value="%s">' % sid )
|
||||
page.add('<input type="hidden" name="borne" value="%s">' % b)
|
||||
|
||||
# titre
|
||||
if '-' in borne.puissance() :
|
||||
# réactivation
|
||||
page.add('<b><u>%s</u></b> <font color="red">(borne désactivée)</font>' % borne.Nom().encode('iso-8859-15'))
|
||||
page.add('<input type="hidden" name="action" value="active">')
|
||||
else :
|
||||
# désctivation
|
||||
page.add('<b><u>%s</u></b> <font color="green">(borne activée)</font>' % borne.Nom().encode('iso-8859-15'))
|
||||
page.add('<input type="hidden" name="action" value="desactive">')
|
||||
page.add('<br>')
|
||||
|
||||
# commentaires
|
||||
page.add('<table><tr><td width=\"20\"> </td><td>')
|
||||
page.add('<br>'.join( filter(lambda x : re.match("^\<.*\>", x) == None, borne.info() ) ).encode('iso-8859-15'))
|
||||
page.add('</td></tr></table>')
|
||||
|
||||
# bouton de validation
|
||||
if '-' in borne.puissance() :
|
||||
page.add('<input type="submit" value="Réactiver %s">' % b)
|
||||
else :
|
||||
page.add('<input type="submit" value="Désactiver %s">' % b)
|
||||
|
||||
# fin du formulaire
|
||||
page.add('</form>')
|
||||
|
||||
# menu de fin de page
|
||||
page.add( "<center><table><tr><td>%s</td><td>%s</td><td>%s</td></tr></center>" % ( bouton(url,sid,'liste-bornes','Actualiser'), bouton_menu, bouton_quitter ) )
|
||||
action = ''
|
||||
|
||||
######################################################
|
||||
# page : erreur de droits
|
||||
|
||||
# si on a encore quelque chose à afficher c'est qu'il y une erreur
|
||||
# on colle ca sur la faute des droits
|
||||
if action not in [ 'index', 'logout', '' ] :
|
||||
page.add("<font color=\"red\">Vous n'avez pas le droits d'effectuer cette opération</font><br><br>\n")
|
||||
page.add('<center><a href="javascript:history.go(-1)">Retour</a></center><br>')
|
||||
action = ''
|
||||
|
||||
######################################################
|
||||
# page : index
|
||||
|
||||
if action == 'index' :
|
||||
# menu principal
|
||||
page.sous_titre("Menu principal")
|
||||
if bornes_modifiables :
|
||||
page.add('<a href="?sid=%s&action=liste-bornes">Activation/désactivation d\'une borne</a><br>' % sid )
|
||||
# menu de bas de page
|
||||
page.add("<center>%s</center>" % bouton_quitter )
|
||||
|
||||
######################################################
|
||||
# page : logout
|
||||
|
||||
if action == 'logout' :
|
||||
log(sess.data['user'] + ' s\'est déconnecté' )
|
||||
page.sous_titre('Session fermée...')
|
||||
sess.destroy()
|
||||
|
||||
######################################################
|
||||
# fin du script
|
||||
page.sendtobrowser()
|
101
archive/wifi/wifiweb/html.py
Normal file
101
archive/wifi/wifiweb/html.py
Normal file
|
@ -0,0 +1,101 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: iso-8859-15 -*-
|
||||
|
||||
class html :
|
||||
|
||||
def __init__ (self) :
|
||||
self._titre = ''
|
||||
self._sous_titre = ''
|
||||
self._corp = ''
|
||||
self._refresh = 0
|
||||
|
||||
def titre(self, titre = None) :
|
||||
""" Définit ou retourne le titre """
|
||||
if titre != None :
|
||||
self._titre = titre
|
||||
return self._titre
|
||||
|
||||
def sous_titre (self, sous_titre = None) :
|
||||
""" Définit ou retourne le sous titre """
|
||||
if sous_titre != None :
|
||||
self._sous_titre = sous_titre
|
||||
return self._sous_titre
|
||||
|
||||
def refresh (self, refresh = None) :
|
||||
""" Définit ou retourne la durée du refresh """
|
||||
|
||||
if _refresh != None :
|
||||
self._refresh = _refresh
|
||||
return self._refresh
|
||||
|
||||
def corp (self, corp = None) :
|
||||
""" Définit ou retourne le contenu du corp """
|
||||
if corp != None :
|
||||
self._corp = corp
|
||||
return self._corp
|
||||
|
||||
def add (self, string) :
|
||||
""" Ajoute une ligne au corp de la page """
|
||||
self._corp += string + "\n"
|
||||
|
||||
def make (self) :
|
||||
""" Génère la page HTML finiale """
|
||||
|
||||
page = ""
|
||||
|
||||
page += "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
|
||||
page += "<html lang=\"fr\">\n"
|
||||
|
||||
# en-têtes de la page
|
||||
#####################
|
||||
|
||||
page += "<head>\n"
|
||||
page += " <title>%s</title>\n" % self._titre
|
||||
if self._refresh :
|
||||
page += " <meta http-equiv=\"refresh\" content=\"%s\">\n" % str(self._refresh)
|
||||
page += " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">\n"
|
||||
page += "</head>\n\n"
|
||||
|
||||
# début du corp de la page
|
||||
##########################
|
||||
|
||||
page += "<body background=\"http://www.crans.org/styles/style2_left.png\" leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\" style=\"background-repeat:repeat-y\">\n"
|
||||
page += "<img src=\"http://www.crans.org/styles/style2_top.png\" alt=\"En_tete\"><br>\n\n"
|
||||
|
||||
# division du titre
|
||||
page += "<div id=\"Titre\" style=\"position:absolute; left:580px; top:70px; width:400px;height:34px; z-index:2\">\n"
|
||||
page += "<font size=\"5\"><b>%s</b></font>\n" % self._titre
|
||||
page += "</div>\n\n"
|
||||
|
||||
# division du sous titre
|
||||
page += "<div id=\"Sous-titre\" style=\"position:absolute; left:380px; top:140px; width:500px;height:34px; z-index:2\">\n"
|
||||
page += "<font size=\"4\"><u>%s</u></font>\n" % self._sous_titre
|
||||
page += "</div>\n\n"
|
||||
|
||||
# division du contenu
|
||||
page += "<div id=\"Contenu\" style=\"position:absolute; left:245px; top:190px; right:16px; z-index:1; overflow: visible; visibility: visible; background-color: #FFFFFF; layer-background-color: #FFFFFF;\">\n"
|
||||
page += self._corp
|
||||
page += "</div>\n\n"
|
||||
|
||||
# fin de la page
|
||||
################
|
||||
|
||||
page += "</body>\n"
|
||||
page += "</html>\n"
|
||||
|
||||
return page
|
||||
|
||||
def sendheaderstobrowser (self) :
|
||||
""" Envoie les entetes au navigateur """
|
||||
print "content-type: text/html"
|
||||
print
|
||||
|
||||
def sendtobrowser (self) :
|
||||
""" Envoie la page au navigateur """
|
||||
print self.make()
|
||||
|
||||
def savetofile (self, fichier) :
|
||||
""" Enregistre la page dans un fichier """
|
||||
f = open(fichier,'w')
|
||||
f.write( self.make() )
|
||||
f.close()
|
91
archive/wifi/wifiweb/session.py
Normal file
91
archive/wifi/wifiweb/session.py
Normal file
|
@ -0,0 +1,91 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: iso-8859-15 -*-
|
||||
|
||||
import os, random
|
||||
from time import time
|
||||
|
||||
class session :
|
||||
|
||||
def __init__ (self, sid = None) :
|
||||
"""
|
||||
Si sid est fournit, on regarde si la session est valide ;
|
||||
on soulève un exeption si il y a un problème
|
||||
|
||||
Si sid n'est pas fourni un créé une nouvelle session
|
||||
"""
|
||||
self.save = True
|
||||
|
||||
if sid :
|
||||
|
||||
# on vérifie la validité
|
||||
if not os.access( self._sess_file(sid), os.W_OK ) :
|
||||
raise ValueError, 'Session inconnue'
|
||||
|
||||
# on exporte le sid
|
||||
self.sid = sid
|
||||
|
||||
# on lit les données
|
||||
self.data = {}
|
||||
f = open(self._sess_file(sid))
|
||||
for i in f.readlines() :
|
||||
if not i.strip() :
|
||||
continue
|
||||
key = i.split(' ')[0]
|
||||
value = ' '.join(i.split(' ')[1:]).strip()
|
||||
self.data[key] = value
|
||||
|
||||
if int(self.data['perime']) < int(time()) :
|
||||
self.destroy()
|
||||
raise ValueError, 'Session périmée'
|
||||
|
||||
else :
|
||||
|
||||
# on créé un nouveau sid
|
||||
self.data = {}
|
||||
ok = False
|
||||
while not ok :
|
||||
sid = ''.join( [ random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for i in range(0,30) ])
|
||||
# est ce que la session existe ?
|
||||
if not os.path.exists(self._sess_file(sid)) :
|
||||
# on créé un nouveau fichier avec un timeout de 60
|
||||
f = os.open(self._sess_file(sid), os.O_WRONLY + os.O_CREAT , 0600)
|
||||
f
|
||||
# on valide
|
||||
ok = True
|
||||
self.sid = sid
|
||||
|
||||
# on initialise les données
|
||||
self.data = {'timeout' : '600'}
|
||||
|
||||
def _sess_file (self, sid = None) :
|
||||
""" Retourne le nom du fichier correspondant à la session """
|
||||
if not sid :
|
||||
sid = self.sid
|
||||
return '/tmp/pysession-%s' % sid
|
||||
|
||||
def __del__ (self) :
|
||||
""" On enregsitre la session à la destruction de l'instance """
|
||||
|
||||
if self.save :
|
||||
# epok de peromption
|
||||
self.data['perime'] = str(int(time() + int(self.data['timeout'])))
|
||||
|
||||
f = open(self._sess_file(), 'w')
|
||||
for k in self.data.keys() :
|
||||
f.write( '%s %s\n' % (k,self.data[k]) )
|
||||
f.close()
|
||||
|
||||
def destroy(self) :
|
||||
""" Supprime la session """
|
||||
self.save = False
|
||||
os.remove( self._sess_file() )
|
||||
|
||||
# on supprime toutes les vieilles sessions
|
||||
for file in os.listdir('/tmp') :
|
||||
if file[0:10] == 'pysession-' :
|
||||
#print file[10:]
|
||||
try :
|
||||
s = session(file[10:])
|
||||
s.save = False
|
||||
except :
|
||||
continue
|
24
archive/wifi/wifiweb/utilisateurs.py
Normal file
24
archive/wifi/wifiweb/utilisateurs.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: iso-8859-15 -*-
|
||||
|
||||
# les mots de passe sont cryptés avec la commande :
|
||||
# python -c "import sha ; print sha.new('***').hexdigest()"
|
||||
|
||||
# Liste des utilisateurs
|
||||
########################
|
||||
# premier champ : autorisation d'inscrire des machines temporaires True|False
|
||||
# champs suivants : préfixe des lieux
|
||||
|
||||
users = {
|
||||
'bilou:b6831110716ea7782b636469b31dc3a695b26386' : ['ens'],
|
||||
'vince||:7bc07c05eebf6726b48f557fcb60b434364034cd' : ['ens'],
|
||||
'xabi:4f1da4cacfd69622c2123d83007a92f9e3de9722' : ['ens'],
|
||||
# Jean-Marc Roussel, pour le laboratoire d'automtique du dgm
|
||||
'labo_auto:920eb1d6bc608a3e8d3a20ccc49bee6c849ccb8b': ['ens_vinci_autom'],
|
||||
# Cécile Durieu
|
||||
'durieu:897712550705c3e02e795e3eea579b0e40c90903' : ['ens_alembert'],
|
||||
# farid.benboudjema, pour le DGC
|
||||
'farid:c710e92d2d15f292f2d5f8c5901fcf91a778590a' : ['ens_vinci_dgc']
|
||||
}
|
||||
|
||||
#
|
Loading…
Add table
Add a link
Reference in a new issue