Revisión 529
Añadido por Alfonso Pastor hace alrededor de 10 años
wifi-ltsp/trunk/autorizaWifiGuardias.py | ||
---|---|---|
#!/usr/bin/python
|
||
# -*- coding: utf-8 -*-
|
||
# Project: wifi-ltsp
|
||
# Module: autorizaWifiGuardias.py
|
||
# Purpose: se usará por el profesor de guardia, y se seleccionará
|
||
# el profesor con clase en ese grupo y ese momento para
|
||
# activar el wifi de los portátiles de los alumnos.
|
||
# Language: Python 2.5
|
||
# Date: 07-Mar-2011.
|
||
# Ver: 07-Mar-2011.
|
||
# Author: Francisco Mora Sánchez
|
||
# Copyright: 2011 - Francisco Mora Sánchez <adminies.maestrojuancalero@edu.juntaextremadura.net>
|
||
#
|
||
# wifi-ltsp is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 3 of the License, or
|
||
# (at your option) any later version.
|
||
# autorizaWifiGuardias is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with wifi-ltsp. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
""" Este programa muestra una lista con los profesores que tienen clase
|
||
a la hora actual, cuando seleccionamos uno de ellos se ejecuta el módulo
|
||
demonio configura_hostapd.py utilizando como parámetro el login del profesor
|
||
seleccionado, que tendrá clase con ese grupo a esa hora, aunque el profesor
|
||
de guardia haya iniciado con su propio login. El módulo sólo se ejecuta
|
||
si el usuario pertenece al grupo teachers. Para llevar a cabo la acción
|
||
se necesita que el módulo configura_hostapd.py, que se ejecuta como root
|
||
en el postlogin de gdm para cada usuario, tenga permisos de ejecución root
|
||
llevándose a cabo esto utilizando el archivo /etc/sudoers, añadiendo una
|
||
línea como:
|
||
|
||
%teachers ALL=NOPASSWD: /usr/bin/configura_hostapd.py
|
||
|
||
Procesa el archivo /wifi/horario.txt y genera un diccionario con los
|
||
logins de profesores que tienen clase a la hora actual, adicionalmente
|
||
consultamos ldap para confeccionar el nombre del profesor, con sus
|
||
nombres y apellidos, de forma que en la caja de selección aparecerán
|
||
los nombres completos en forma Apellidos, Nombre o bien el login
|
||
del profesor. Tenemos que tener en cuenta que el archivo
|
||
/wifi/horario.txt ya existe en la ruta, ya que el script
|
||
configura_hostapd.py se ejecuta en el inicio y lo deja en el lugar
|
||
adecuado.
|
||
|
||
Será responsabilidad de cada administrador o herramienta de gestión ldap
|
||
que el atributo cn de cada objeto de la rama People, perteneciente a cada
|
||
profesor, de ldap que sea un profesor, tenga el nombre en forma "humana".
|
||
Tambien sería deseable que este atributo para los alumnos estuviese en
|
||
esa forma.
|
||
|
||
Francisco Mora Sánchez
|
||
I.E.S. Maestro Juan Calero
|
||
adminies.maestrojuancalero@edu.juntaextremadura.net
|
||
|
||
"""
|
||
|
||
import pygtk
|
||
pygtk.require("2.0")
|
||
import gtk
|
||
import logging
|
||
import subprocess
|
||
import os
|
||
import time
|
||
import ldap
|
||
|
||
LOG_FILENAME = "autorizaWifiGuardias.log"
|
||
|
||
profesores = {}
|
||
|
||
def hora_actual(fecha):
|
||
"""Con esta funcion se obtiene la hora actual del sistema sin los : de forma
|
||
que la 08:45 se representarancomo la 0845"""
|
||
hora= fecha[11:13]+fecha[14:16]
|
||
h=int(hora)
|
||
if (h<int(0000) or h>int(2500)):
|
||
logging.getLogger().error("El formato de la hora del sistema no es el esperado")
|
||
return "9999"
|
||
else:
|
||
return hora
|
||
|
||
def procesahorario(profesores):
|
||
"""con esta funcion generamos el diccionario de profesores con clase a la hora actual,
|
||
además buscamos en el directorio ldap los valores cn en la rama people que deben
|
||
contener los nombres completos de los profesores
|
||
"""
|
||
if not os.path.exists("/wifi/horario.txt"):
|
||
logging.getLogger().error("No hay fichero /wifi/horario.txt en el servidor de aula")
|
||
return ""
|
||
|
||
try:
|
||
horario = open("/wifi/horario.txt","r")
|
||
except:
|
||
logging.getLogger().error("Problemas para leer el archivo /wifi/horario.txt")
|
||
return ""
|
||
|
||
hora = hora_actual(time.asctime())
|
||
#hora = "1241"
|
||
while True:
|
||
linea = horario.readline()
|
||
if not linea:
|
||
break
|
||
else:
|
||
lineasplit = linea.split("|")
|
||
profesor = lineasplit[0]
|
||
if hora>lineasplit[2] and hora<lineasplit[3]:
|
||
if not profesores.has_key(profesor):
|
||
#print "Profesor en horario",profesor," hora",hora
|
||
profesores[profesor] = profesor
|
||
horario.close()
|
||
#ahora procesaremos el diccionario buscando en ldap los cn
|
||
l = ldap.initialize("ldap://ldap")
|
||
|
||
base_dn='ou=People,dc=instituto,dc=extremadura,dc=es'
|
||
#searchFilter = '(uid='+identificador+')'
|
||
searchScope = ldap.SCOPE_SUBTREE
|
||
retrieveAttributes = ['cn']
|
||
|
||
for profesor in profesores.keys():
|
||
nombre = profesor
|
||
try:
|
||
searchFilter = '(uid='+profesor+')'
|
||
ldap_result_id = l.search(base_dn, searchScope, searchFilter, retrieveAttributes)
|
||
result_type, result_data = l.result(ldap_result_id, 0)
|
||
if len(result_data)==0:
|
||
logging.getLogger().error("No encontrado en ldap..."+profesor)
|
||
else:
|
||
resultado=result_data[0]
|
||
except:
|
||
logging.getLogger().error("Error buscando en ldap..."+profesor)
|
||
continue
|
||
|
||
profesores[profesor] = resultado[1]['cn'][0]
|
||
|
||
def userIsTeacher(teachersGroup='teachers'):
|
||
p1 = subprocess.Popen(["id", "-Gn"], stdout=subprocess.PIPE)
|
||
p2 = subprocess.Popen(["grep", teachersGroup], stdin=p1.stdout, stdout=subprocess.PIPE)
|
||
output = p2.communicate()[0]
|
||
return (output != '')
|
||
|
||
class AutorizaWifiGuardias():
|
||
|
||
def delete_event(self, widget, event, data=None):
|
||
print "delete event occurred"
|
||
#con false se cierra la ventana principal, con true no
|
||
return False
|
||
|
||
def destroy(self, widget, data=None):
|
||
gtk.main_quit()
|
||
|
||
def create_model(self):
|
||
store = gtk.ListStore(str, str)
|
||
procesahorario(profesores)
|
||
for profesor in profesores.keys():
|
||
store.append([profesores[profesor], profesor])
|
||
return store
|
||
|
||
def create_columns(self, treeView):
|
||
rendererText = gtk.CellRendererText()
|
||
column = gtk.TreeViewColumn("Nombre y Apellidos", rendererText, text=0)
|
||
column.set_sort_column_id(0)
|
||
treeView.append_column(column)
|
||
|
||
rendererText = gtk.CellRendererText()
|
||
column = gtk.TreeViewColumn("Login del profesor", rendererText, text=1)
|
||
column.set_sort_column_id(1)
|
||
treeView.append_column(column)
|
||
|
||
def on_activated(self, widget, row, col):
|
||
model = widget.get_model()
|
||
try:
|
||
p = subprocess.Popen(["/usr/bin/sudo", "/usr/bin/configura_hostapd.py", model[row][1]])
|
||
except OSError, e:
|
||
logging.getLogger().error("Hay problemas al ejecutar comando activación WIFI")
|
||
self.statusbar.push(0, 'Hay algún problema al activar WIFI')
|
||
return
|
||
self.statusbar.push(0, 'Activado WIFI profesor '+model[row][0])
|
||
|
||
def win_close(self, widget, event, data):
|
||
dialog = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_YES_NO, "¿Quieres salir realmente?")
|
||
dialog.set_title("Atención")
|
||
response = dialog.run()
|
||
dialog.destroy()
|
||
if response == gtk.RESPONSE_YES:
|
||
return False
|
||
else:
|
||
return True
|
||
|
||
def no_profesor(self, widget):
|
||
logging.getLogger().error("Ejecutando programa usuario no profesor")
|
||
md = gtk.MessageDialog(self.window, gtk.DIALOG_DESTROY_WITH_PARENT,
|
||
gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, "Sólo los profesores pueden ejecutar esta aplicación")
|
||
md.run()
|
||
md.destroy()
|
||
|
||
def __init__(self):
|
||
#super(AutorizaWifiGuardias, self).__init__()
|
||
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||
|
||
if not userIsTeacher():
|
||
logging.getLogger().error("Ejecutando programa usuario no profesor")
|
||
self.no_profesor(self)
|
||
self.window.connect('event-after', gtk.main_quit)
|
||
|
||
self.window.set_size_request(500, 600)
|
||
self.window.set_position(gtk.WIN_POS_CENTER)
|
||
|
||
self.window.connect("destroy", self.destroy)
|
||
self.window.connect("delete-event", self.win_close, None)
|
||
self.window.set_title("Autorización WIFI profesores de guardia")
|
||
|
||
self.vbox = gtk.VBox(False, 8)
|
||
|
||
self.label = gtk.Label()
|
||
self.label.set_markup("<b>Haz doble click en profesor sustituido</b>")
|
||
self.vbox.pack_start(self.label, False, False, 0)
|
||
|
||
self.sw = gtk.ScrolledWindow()
|
||
self.sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
|
||
self.sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
||
|
||
self.vbox.pack_start(self.sw, True, True, 0)
|
||
|
||
self.store = self.create_model()
|
||
|
||
self.treeView = gtk.TreeView(self.store)
|
||
self.treeView.connect("row-activated", self.on_activated)
|
||
self.treeView.set_rules_hint(True)
|
||
self.sw.add(self.treeView)
|
||
|
||
self.create_columns(self.treeView)
|
||
|
||
self.statusbar = gtk.Statusbar()
|
||
self.vbox.pack_start(self.statusbar, False, False, 0)
|
||
|
||
self.window.add(self.vbox)
|
||
self.window.show_all()
|
||
|
||
def main():
|
||
logging.basicConfig(level=logging.DEBUG,
|
||
format='%(asctime)s %(levelname)-8s %(message)s',
|
||
datefmt='%a, %d %b %Y %H:%M:%S',
|
||
filename=LOG_FILENAME,
|
||
filemode='w')
|
||
|
||
AutorizaWifiGuardias()
|
||
gtk.main()
|
||
|
||
main()
|
||
wifi-ltsp/trunk/configura_hostapd.py | ||
---|---|---|
#!/usr/bin/python
|
||
# -*- coding: utf-8 -*-
|
||
# Project: wifi-ltsp
|
||
# Module: configura_hostapd.py
|
||
# Purpose: genera un archivo hostapc.accept para dar acceso a internet a los alumnos.
|
||
# Language: Python 2.5
|
||
# Date: 07-Feb-2011.
|
||
# Ver: 07-Feb-2011.
|
||
# Author: Isabel Aparicio Pérez
|
||
# Copyright: 2011 - Isabel Aparicio Pérez <prog5pe@edu.juntaextremadura.net>
|
||
#
|
||
# wifi-ltsp is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 3 of the License, or
|
||
# (at your option) any later version.
|
||
# Script2 is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with wifi-ltsp. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
""" Este programa genera el archivo hostapd.access necesario para que en el momento del logueo del
|
||
profesor se de acceso a internet a los alumnos que tienen clase en esa hora con ese profesor. Para ello
|
||
tenemos que recoger el dia de la semana y la hora actual que tiene el servidor de aula y con el dia actual
|
||
buscar en el servidor nfs el fichero del dia de la semana que corresponde con el dia concreto. El fichero
|
||
descargado del servidor nfs se almacena en el servidor de aula en la ruta /wifi con el nombre horario.txt.
|
||
Tambien controlamos el usuario que esta logueado en ese preciso momento en el servidor. A partir del usuario
|
||
logueado, de la hora del sistema y del fichero descargado del servidor nfs se genera el fichero hostapd.access
|
||
con las mac de los alumnos correspondientes.
|
||
|
||
Isabel Aparicio Pérez
|
||
Consejería de Educacion.
|
||
prog5pe@edu.juntaextremadura.net
|
||
|
||
"""
|
||
|
||
import time
|
||
import urllib
|
||
import os
|
||
import sys
|
||
from parsehostapd import parsehostapd
|
||
import socket
|
||
import logging
|
||
import subprocess
|
||
from shutil import copy
|
||
|
||
LOG_FILENAME= "/var/log/configura-hostapd.log"
|
||
fecha=[]
|
||
ip=[]
|
||
dia_semana={"Mon":"lunes.txt","Tue":"martes.txt","Wed":"miercoles.txt","Thu":"jueves.txt","Fri":"viernes.txt"}
|
||
|
||
|
||
def dia_actual():
|
||
"""con esta funcion se obtiene la fecha actual que tiene el servidor de aula"""
|
||
hoy = time.asctime()
|
||
return hoy
|
||
|
||
def fichero_semana(fecha1):
|
||
"""Con esta funcion se obtiene la parte de la fecha actual que corresponde con el dia de la semana"""
|
||
dia= fecha1[0:3]
|
||
if dia not in ["Mon","Tue","Wed","Thu","Fri"]:
|
||
logging.getLogger().error("El formato de la fecha del sistema no es el esperado")
|
||
return ""
|
||
else:
|
||
fichero=dia_semana[dia]
|
||
return fichero
|
||
|
||
def hora_actual(fecha1):
|
||
"""Con esta funcion se obtiene la hora actual del sistema sin los : de forma que la 08:45 se representaran
|
||
como la 0845"""
|
||
hora= fecha1[11:13]+fecha1[14:16]
|
||
h=int(hora)
|
||
if (h<int(0000) or h>int(2500)):
|
||
logging.getLogger().error("El formato de la hora del sistema no es el esperado")
|
||
return "9999"
|
||
else:
|
||
return hora
|
||
|
||
|
||
def descargar_fichero(fichero):
|
||
"""funcion que se encarga de descargar el fichero del dia de la semana correspondiente al dia actual del
|
||
servidor nfs y colocarlo en la ubicacion correcta en el servidor de terminales con el nombre de horario.txt"""
|
||
archivo="http://servidor/wifi/"+fichero
|
||
print archivo
|
||
destino="/wifi/horario.txt"
|
||
destino2="/wifi"
|
||
if not os.path.exists(destino2):
|
||
logging.getLogger().debug("La ruta destino no existe y hay que crearla")
|
||
try:
|
||
os.makedirs(destino2)
|
||
except OSError:
|
||
logging.getLogger().error("Hay algun error a la hora de crear el directorio /wifi en el servidor de aula")
|
||
try:
|
||
urllib.urlretrieve(archivo, destino)
|
||
except:
|
||
logging.getLogger().error("No hay acceso al servidor para encontrar el fichero de horario")
|
||
return ""
|
||
return destino
|
||
|
||
|
||
def devuelve_usuario():
|
||
"""con esta funcion recogemos el usuario que esta logueado en ese momento en el ordenador, seguira intentandolo
|
||
hasta que se loguee antes"""
|
||
resultado = sys.argv[1]
|
||
return resultado
|
||
|
||
def crea_hostapd(destino,resultado,hora):
|
||
"""con esta funcion generamos el fichero hostapd con las mac correspondientes a los alumnos a los que se
|
||
les va a dar acceso a internet y lo colocamos en la ruta correcta."""
|
||
if not os.path.exists(destino):
|
||
logging.getLogger().error("Hay un error el el fichero horario.txt en el servidor de aula")
|
||
return ""
|
||
else:
|
||
try:
|
||
copy("/etc/hostapd/hostapd.accept","/etc/hostapd/hostapd.accept.bak")
|
||
except:
|
||
pass
|
||
f=open(destino,"r")
|
||
if not os.path.exists("/etc/hostapd"):
|
||
try:
|
||
os.makedirs("/etc/hostapd")
|
||
except IOError:
|
||
logging.getLogger().error("Ha habido algun error a la hora de crear el directorio /etc/hostapd")
|
||
return ""
|
||
if not os.access("/etc/hostapd", os.W_OK):
|
||
logging.getLogger().error("No tiene permisos de escritura sobre el directorio /etc/hostapd")
|
||
return ""
|
||
else:
|
||
g=open("/etc/hostapd/hostapd.accept","w")
|
||
|
||
esta_en_horario=False
|
||
while True:
|
||
dato=f.readline()
|
||
if not dato:
|
||
break
|
||
else:
|
||
lin=dato.split("|")
|
||
if lin[0]==resultado:
|
||
if hora>lin[2] and hora<lin[3]:
|
||
g.write(lin[1])
|
||
g.write("\n")
|
||
esta_en_horario=True
|
||
f.close()
|
||
g.close()
|
||
|
||
#si un profesor de guardia hace login, se autorizan automáticamente los
|
||
#alumnos que hubiera autorizado el profesor anterior:
|
||
if not esta_en_horario:
|
||
try:
|
||
copy("/etc/hostapd/hostapd.accept.bak","/etc/hostapd/hostapd.accept")
|
||
except:
|
||
pass
|
||
|
||
return g
|
||
|
||
def inicia_hostapd():
|
||
subprocess.Popen(["ifconfig","wlan0","up"])
|
||
subprocess.Popen(["invoke-rc.d","hostapd","restart"])
|
||
|
||
def userIsTeacher(user_name):
|
||
p1 = subprocess.Popen(["id", "-Gn",user_name], stdout=subprocess.PIPE)
|
||
p2 = subprocess.Popen(["grep", 'teachers'], stdin=p1.stdout, stdout=subprocess.PIPE)
|
||
output = p2.communicate()[0]
|
||
return (output != '')
|
||
|
||
if __name__ == '__main__':
|
||
logging.basicConfig(level=logging.DEBUG,
|
||
format='%(asctime)s %(levelname)-8s %(message)s',
|
||
datefmt='%a, %d %b %Y %H:%M:%S',
|
||
filename=LOG_FILENAME)
|
||
|
||
if len(sys.argv)>1:
|
||
dia_hoy=""
|
||
hora=""
|
||
user=""
|
||
fich=""
|
||
hos=""
|
||
res=""
|
||
f=""
|
||
|
||
dia_hoy=dia_actual()
|
||
hora=hora_actual(dia_hoy)
|
||
fich=fichero_semana(dia_hoy)
|
||
f=descargar_fichero(fich)
|
||
if f!="":
|
||
user=devuelve_usuario()
|
||
if userIsTeacher(user):
|
||
hos=crea_hostapd(f,user,hora)
|
||
else: #login de un alumno
|
||
subprocess.Popen(["invoke-rc.d","hostapd","stop"]).wait()
|
||
sys.exit(0)
|
||
|
||
if hos=="":
|
||
logging.getLogger().error("Error al generar las mac autorizadas")
|
||
|
||
|
||
#Aquí metemos ahora la reconfiguración de hostapd.conf con la parte
|
||
#hecha por Francisco Mora
|
||
hostapdconf="/etc/hostapd/hostapd.conf"
|
||
|
||
canaloptimo = parsehostapd.selectbestchannel(True)
|
||
|
||
ssid = socket.gethostname()
|
||
pos = ssid.find(".")
|
||
if pos > -1:
|
||
ssid = ssid[:pos]
|
||
pos = ssid.find("-pro")
|
||
if pos > -1:
|
||
ssid = ssid[:pos]
|
||
try:
|
||
#Abre el archivo para lectura de datos
|
||
archivoLectura = open(hostapdconf,"r")
|
||
lineas = archivoLectura.readlines()
|
||
archivoLectura.close()
|
||
except (RuntimeError, TypeError, NameError, IOError):
|
||
logging.getLogger().error("Error en la ubicacion o nombre del archivo")
|
||
sys.exit(0) #salimos con 0 para no fastidiar gdm
|
||
#Modifica la cadena del channel y ssid
|
||
encontradoChannel = False
|
||
encontradoSsid = False
|
||
for numlinea in range(0, len(lineas)):
|
||
linea = lineas[numlinea]
|
||
#comprobamos si estamos en channel o en ssid
|
||
if linea[:7] == "channel":
|
||
encontradoChannel = True
|
||
lineas[numlinea] = "channel="+str(canaloptimo)+"\n"
|
||
if linea[:4] == "ssid":
|
||
encontradoSsid = True
|
||
lineas[numlinea] = "ssid="+ssid+"\n"
|
||
if not encontradoChannel:
|
||
lineas.append("channel="+str(canaloptimo)+"\n")
|
||
if not encontradoSsid:
|
||
lineas.append("ssid="+ssid+"\n")
|
||
|
||
#Abre el archivo para escritura de datos
|
||
archivoEscritura = open(hostapdconf,"w")
|
||
archivoEscritura.writelines(lineas)
|
||
archivoEscritura.close()
|
||
logging.getLogger().debug('Establecido el canal %s con ESSID %s' % (canaloptimo,ssid))
|
||
|
||
|
||
|
||
res=inicia_hostapd()
|
||
|
||
wifi-ltsp/trunk/setup.py | ||
---|---|---|
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
from distutils.core import setup
|
||
import os
|
||
|
||
datafiles = []
|
||
|
||
|
||
setup(name='wifi-ltsp',
|
||
version='0.1',
|
||
description='Archivos de configuración de hostapd con wifi',
|
||
long_description = """Really long text here.""",
|
||
author = 'José L. Redrejo Rodríguez, Francisco Mora Sánchez y Elisa Aparicio Pérez',
|
||
author_email = 'jredrejo@debian.org',
|
||
license = "GNU GPLv3",
|
||
packages=['parsehostapd'],
|
||
package_dir={'parsehostapd': 'parsehostapd/'},
|
||
url = 'http://desarrollo.educarex.es/linex/projects/servidoressecundaria/repository/show/wifi-ltsp',
|
||
# Those are going to be installed on /usr/bin/
|
||
scripts=['configura_hostapd.py','autorizaWifiGuardias.py'],
|
||
|
||
data_files=datafiles
|
||
)
|
||
|
wifi-ltsp/trunk/parsehostapd/parsehostapd.py | ||
---|---|---|
#!/usr/bin/python
|
||
# -*- coding: utf-8 -*-
|
||
# Project: wifi-ltsp
|
||
# Module: parsehostapd.py
|
||
# Purpose: Parsea el fichero /etc/hostapd/hostapd.conf
|
||
# Language: Python 2.5
|
||
# Date: 26-Enero-2011.
|
||
# Ver: 07-Feb-2011.
|
||
# Author: Francisco Mora Sánchez
|
||
# Copyright: 2011 - Francisco Mora Sánchez <adminies.maestrojuancalero@edu.juntaextremadura.net>
|
||
#
|
||
# wifi-ltsp is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 3 of the License, or
|
||
# (at your option) any later version.
|
||
# Script2 is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with wifi-ltsp. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
""" Módulo que contiene la función selectbestchannel()
|
||
Función que escanea el espectro de canales de redes
|
||
wifi y nos devuelve el canal más idóneo para ser utilizado en
|
||
el lugar en que estamos.
|
||
|
||
La función admite dos parámetros
|
||
|
||
Utiliza la libreria pythonwifi y está basado en uno de los ejemplos
|
||
incluidos en la libreria
|
||
Debe ser ejecutado como root
|
||
|
||
El algoritmo utilizado se basa en sumar las redes que existen en cada
|
||
canal y a continuación calcular las sumas de los solapes de las redes
|
||
centradas en canales, patrón 1-6-11, escogeremos el canal cuyo valor
|
||
de las sumas sea menor.
|
||
|
||
Los canales que se solapan en el patrón 1-6-11 son los siguientes:
|
||
|
||
Canal Canales que se solapan
|
||
1 1-5
|
||
2 1-6
|
||
3 1-7
|
||
4 1-8
|
||
5 1-9
|
||
6 2-10
|
||
7 3-11
|
||
8 4-12
|
||
9 5-13
|
||
10 6-13
|
||
11 7-13
|
||
12 8-13
|
||
13 9-13
|
||
|
||
|
||
Francisco Mora Sánchez
|
||
IES Maestro Juan Calero
|
||
adminies.maestrojuancalero@edu.juntaextremadura.net
|
||
|
||
|
||
"""
|
||
|
||
import sys
|
||
import os
|
||
import socket
|
||
|
||
#from pythonwifi.iwlibs import Wireless, getWNICnames
|
||
|
||
import escanea
|
||
|
||
def actualizadatosescaneo(datosescaneo, canal, bssid, essid, calidad, intensidad):
|
||
""" Actualizamos diccionario con los datos recogidos del
|
||
escaneado, comprobamos que no hemos insertado
|
||
previamente la red, comprobando el bssid del AP
|
||
"""
|
||
if not datosescaneo.has_key(canal):
|
||
#insertamos el canal inicializando los campos
|
||
datosescaneo[canal] = [1, [[bssid,calidad,intensidad]], 0]
|
||
else:
|
||
#comprobemos que no existe ese bssid en el diccionario
|
||
#listabssid = datosescaneo[canal][1]
|
||
listabssid = [bssids[0] for bssids in datosescaneo[canal][1]]
|
||
if not bssid in listabssid:
|
||
#no está en la lista, añadimos y aumentamos el contador de redes
|
||
datosescaneo[canal][0] = datosescaneo[canal][0] + 1
|
||
datosescaneo[canal][1].append([bssid,calidad,intensidad])
|
||
|
||
def procesadatosescaneo(datosescaneo):
|
||
""" Sumamos las redes solapadas centradas en los canales, basándonos
|
||
en el patrón 1-6-11
|
||
"""
|
||
adyacentes = {1:[1,2,3,4,5],2:[1,2,3,4,5,6],3:[1,2,3,4,5,6,7],4:[1,2,3,4,5,6,7,8],5:[1,2,3,4,5,6,7,8,9], \
|
||
6:[2,3,4,5,6,7,8,9,10],7:[3,4,5,6,7,8,9,10,11],8:[4,5,6,7,8,9,10,11,12],9:[5,6,7,8,9,10,11,12,13], \
|
||
10:[6,7,8,9,10,11,12,13],11:[7,8,9,10,11,12,13],12:[8,9,10,11,12,13],13:[9,10,11,12,13]}
|
||
|
||
#Rellenamos canales faltantes
|
||
for canal in range(1, 14):
|
||
if not datosescaneo.has_key(canal):
|
||
datosescaneo[canal] = [0, [], 0]
|
||
|
||
#Sumemor las redes solapadas
|
||
for canal in range(1, 14):
|
||
for adyacente in adyacentes[canal]:
|
||
datosescaneo[canal][2] = datosescaneo[canal][2] + datosescaneo[adyacente][0]
|
||
|
||
def seleccionacanaloptimo(datosescaneo):
|
||
""" Procesamos diccionario y retornamos el canal óptimo,
|
||
aquel cuyo valor de numero de redes totales solapadas
|
||
centradas es el mínimo
|
||
"""
|
||
#El mejor canal, es el menor valor de los solapes de las redes centradas en canales
|
||
canaloptimo = 1
|
||
valor = datosescaneo[1][2]
|
||
for canal in range(1, 14):
|
||
if datosescaneo[canal][2] < valor:
|
||
canaloptimo = canal
|
||
valor = datosescaneo[canal][2]
|
||
return canaloptimo
|
||
|
||
def selectbestchannel(verbose = False):
|
||
""" Creamos diccionario para almacenar datos, la key principal es
|
||
es el canal, y para cada canal hay una lista en
|
||
la que se almacena el número de redes detectadas, sus BSSID junto
|
||
a su potencia e intensidad, además se almacenará
|
||
y el número de redes que se solapan con las redes centradas en canales
|
||
según patrón 1-6-11.
|
||
Controlaremos que no se dupliquen los canales cuando hay más de un interfaz wifi
|
||
comparando los BSSID para este menester
|
||
"""
|
||
|
||
#Esta seria la estructura que obtendriamos de nuestro escaneado
|
||
#{1:[3, [["MACAP1",70,-56], ["MACAP2",65,-61], ["MACAP3",60,-66]], 0],
|
||
# 2:[2, [["MACAP4",75,-51], ["MACAP5",65,-61]], 0]
|
||
# 3:[1, [["MACAP6",80,-45]], 0],
|
||
# 4:[1, [["MACAP7",60,-66]], 0]}
|
||
datosescaneo = {}
|
||
if verbose:
|
||
print "Escaneando redes WIFI..."
|
||
index = 1
|
||
for ifname in escanea.getWirelessInterfaces():
|
||
if verbose:
|
||
print " Escaneado de la interfaz %-8.16s" % (ifname, )
|
||
otros_datos_escaneo = escanea.ObtieneRedes(ifname)
|
||
if len(otros_datos_escaneo.keys()) == 0:
|
||
if verbose:
|
||
print "%-8.16s Escaneado sin resultados" % (ifname, )
|
||
for bssid in otros_datos_escaneo.keys():
|
||
if verbose:
|
||
print " Red: %02d - Canal: %s BSSID: %s ESSID: %s Quality: %s Signal Strength: %s" % \
|
||
(index, otros_datos_escaneo[bssid]['canal'], bssid, otros_datos_escaneo[bssid]['essid'], otros_datos_escaneo[bssid]['calidad'], otros_datos_escaneo[bssid]['intensidad'])
|
||
#vamos a actualizar nuestro diccionario
|
||
actualizadatosescaneo(datosescaneo, int(otros_datos_escaneo[bssid]['canal']), bssid, otros_datos_escaneo[bssid]['essid'], otros_datos_escaneo[bssid]['calidad'], otros_datos_escaneo[bssid]['intensidad'])
|
||
index = index +1
|
||
#para pruebas
|
||
#datosescaneo = {1:[2, [["01",99,-99],["02",98,-98]], 0], 6:[3, [["03",97,-97],["04",96,-96],["05",95,-95]], 0], 11:[1, ["06",94,-94], 0]}
|
||
procesadatosescaneo(datosescaneo)
|
||
canaloptimo = seleccionacanaloptimo(datosescaneo)
|
||
if verbose:
|
||
print "\nTabla de datos obtenida:"
|
||
print datosescaneo
|
||
print "\n"
|
||
print "El canal óptimo es el: ", canaloptimo
|
||
|
||
return canaloptimo
|
||
|
||
if __name__ == "__main__":
|
||
""" Comprobaremos que se ha pasado la ruta al archivo hostapd.conf
|
||
El archivo hostapd.conf debe contener la cadena 'canalseleccionado'
|
||
que será reemplazada por la salida de la función selectchannelwifi().
|
||
|
||
Además el SSID es el nombre de equipo menos la cadena '-pro', y
|
||
la cadena a buscar en el archivo hostapd.conf es 'ssidseleccionado'.
|
||
"""
|
||
if len(sys.argv) == 1:
|
||
print 'uso: ./parsehostapd.py /ruta/al/archivo/hostapd.conf'
|
||
sys.exit(1)
|
||
#Comprobemos la existencia del archivo
|
||
hostapdconf = sys.argv[1]
|
||
if not os.path.exists(hostapdconf):
|
||
print "El archivo",hostapdconf,"no existe"
|
||
exit(2)
|
||
print "Procesando archivo",hostapdconf
|
||
""" Aquí llamamos a la función desarrollada en este módulo
|
||
para asignar el canal de transmisión óptimo,
|
||
si ponemos True en el parámetro podremos ver las redes
|
||
que se detectan...
|
||
"""
|
||
canaloptimo = selectbestchannel(True)
|
||
|
||
ssid = socket.gethostname()
|
||
pos = ssid.find(".")
|
||
if pos > -1:
|
||
ssid = ssid[:pos]
|
||
pos = ssid.find("-pro")
|
||
if pos > -1:
|
||
ssid = ssid[:pos]
|
||
try:
|
||
#Abre el archivo para lectura de datos
|
||
archivoLectura = open(hostapdconf,"r")
|
||
lineas = archivoLectura.readlines()
|
||
archivoLectura.close()
|
||
except (RuntimeError, TypeError, NameError, IOError):
|
||
print "Error en la ubicacion o nombre del archivo"
|
||
exit()
|
||
#Modifica la cadena del channel y ssid
|
||
encontradoChannel = False
|
||
encontradoSsid = False
|
||
for numlinea in range(0, len(lineas)):
|
||
linea = lineas[numlinea]
|
||
#comprobamos si estamos en channel o en ssid
|
||
if linea[:7] == "channel":
|
||
encontradoChannel = True
|
||
lineas[numlinea] = "channel="+str(canaloptimo)+"\n"
|
||
if linea[:4] == "ssid":
|
||
encontradoSsid = True
|
||
lineas[numlinea] = "ssid="+ssid+"\n"
|
||
if not encontradoChannel:
|
||
lineas.append("channel="+str(canaloptimo)+"\n")
|
||
if not encontradoSsid:
|
||
lineas.append("ssid="+ssid+"\n")
|
||
|
||
#Abre el archivo para escritura de datos
|
||
archivoEscritura = open(hostapdconf,"w")
|
||
archivoEscritura.writelines(lineas)
|
||
archivoEscritura.close()
|
||
print "El canal establecido es",canaloptimo
|
||
print "El SSID establecido es",ssid
|
||
print "Se ha procesado el archivo",hostapdconf
|
||
wifi-ltsp/trunk/parsehostapd/escanea.py | ||
---|---|---|
#!/usr/bin/python
|
||
# -*- coding: utf-8 -*-
|
||
# Project: wifi-ltsp
|
||
# Module: escanea.py
|
||
# Purpose: Busca el canal libre más adecuado para la wifi
|
||
# Language: Python 2.5
|
||
# Date: 03-Feb-2011.
|
||
# Ver: 07-Feb-2011.
|
||
# Author: Francisco Mora Sánchez
|
||
# Copyright: 2011 - Francisco Mora Sánchez <adminies.maestrojuancalero@edu.juntaextremadura.net>
|
||
#
|
||
# wifi-ltsp is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 3 of the License, or
|
||
# (at your option) any later version.
|
||
# Script2 is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with wifi-ltsp. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
|
||
"""Módulo auxiliar para obtener información a través
|
||
del comando iwlist, perteneciente a las herramientas
|
||
wireless-tools
|
||
|
||
Francisco Mora Sánchez
|
||
IES Maestro Juan Calero
|
||
adminies.maestrojuancalero@edu.juntaextremadura.net
|
||
|
||
|
||
"""
|
||
|
||
import os
|
||
import re
|
||
import locale
|
||
import time
|
||
from subprocess import Popen, STDOUT, PIPE, call
|
||
|
||
# Expresiones Regulares.
|
||
_re_mode = (re.I | re.M | re.S)
|
||
essid_pattern = re.compile('.*ESSID:"?(.*?)"?\s*\n', _re_mode)
|
||
ap_mac_pattern = re.compile('.*Address: (.*?)\n', _re_mode)
|
||
channel_pattern = re.compile('.*Channel:?=? ?(\d\d?)', _re_mode)
|
||
strength_pattern = re.compile('.*Quality:?=? ?(\d+)\s*/?\s*(\d*)', _re_mode)
|
||
altstrength_pattern = re.compile('.*Signal level:?=? ?(\d+)\s*/?\s*(\d*)', _re_mode)
|
||
signaldbm_pattern = re.compile('.*Signal level:?=? ?(-\d\d*)', _re_mode)
|
||
freq_pattern = re.compile('.*Frequency:(.*?)\n', _re_mode)
|
||
|
||
def to_unicode(x):
|
||
""" Convierte una cadena a codificación utf-8. """
|
||
# Si ésta es una cadena unicode, la codifica y la devuelve
|
||
if not isinstance(x, basestring):
|
||
return x
|
||
if isinstance(x, unicode):
|
||
return x.encode('utf-8')
|
||
encoding = locale.getpreferredencoding()
|
||
try:
|
||
ret = x.decode(encoding).encode('utf-8')
|
||
except UnicodeError:
|
||
try:
|
||
ret = x.decode('utf-8').encode('utf-8')
|
||
except UnicodeError:
|
||
try:
|
||
ret = x.decode('latin-1').encode('utf-8')
|
||
except UnicodeError:
|
||
ret = x.decode('utf-8', 'replace').encode('utf-8')
|
||
|
||
return ret
|
||
|
||
def EjecutaRegex(regex, cadena):
|
||
""" ejecuta búsqueda de expresión regular en una cadena """
|
||
m = regex.search(cadena)
|
||
if m:
|
||
return m.groups()[0]
|
||
else:
|
||
return None
|
||
|
||
def Ejecuta(comando, include_stderr=False, return_pipe=False,
|
||
return_obj=False, return_retcode=True):
|
||
""" Ejecuta un comando.
|
||
|
||
Ejecuta el comando dado, retornando la salida del programa
|
||
o un pipe para leer la salida.
|
||
|
||
argumentos --
|
||
comando - Comando a ejecutar
|
||
include_std_err - Boleano, especifica si la salida de error debe
|
||
ser incluida en el pipe.
|
||
return_pipe - Boleano, especifica si el pipe del comando se
|
||
devuelve. Si es False, todo lo que devolverá
|
||
es la cadena de salida del comando.
|
||
return_obj - Si True, Ejecuta devolverá el objeto Popen
|
||
para el comando que se ha ejecutado.
|
||
|
||
"""
|
||
if not isinstance(comando, list):
|
||
comando = to_unicode(str(comando))
|
||
comando = comando.split()
|
||
if include_stderr:
|
||
err = STDOUT
|
||
fds = True
|
||
else:
|
||
err = None
|
||
fds = False
|
||
if return_obj:
|
||
std_in = PIPE
|
||
else:
|
||
std_in = None
|
||
|
||
# Debemos asegurarnos que los resultados del comando ejecutado
|
||
# están en inglés, así ajustaremos un entorno temporal.
|
||
tmpenv = os.environ.copy()
|
||
tmpenv["LC_ALL"] = "C"
|
||
tmpenv["LANG"] = "C"
|
||
|
||
try:
|
||
f = Popen(comando, shell=False, stdout=PIPE, stdin=std_in, stderr=err,
|
||
close_fds=fds, cwd='/', env=tmpenv)
|
||
except OSError, e:
|
||
print "Fallo ejecuando comando %s : %s" % (str(comando), str(e))
|
||
return ""
|
||
|
||
if return_obj:
|
||
return f
|
||
if return_pipe:
|
||
return f.stdout
|
||
else:
|
||
return f.communicate()[0]
|
||
|
||
def FrecuenciaACanal(frecuencia):
|
||
""" Transforma una frecuencia a canal.
|
||
|
||
Nota: Esta función es una búsqueda en diccionario, por lo que
|
||
la frecuencia debe estar en el diccionario para que pueda
|
||
devolverse un canal válido.
|
||
|
||
Parámetros:
|
||
frecuencia -- cadena conteniendo la frecuencia
|
||
|
||
Devuelve:
|
||
El número de canal, o None si no se encuentra.
|
||
"""
|
||
ret = None
|
||
freq_dict = {'2.412 GHz': 1, '2.417 GHz': 2, '2.422 GHz': 3,
|
||
'2.427 GHz': 4, '2.432 GHz': 5, '2.437 GHz': 6,
|
||
'2.442 GHz': 7, '2.447 GHz': 8, '2.452 GHz': 9,
|
||
'2.457 GHz': 10, '2.462 GHz': 11, '2.467 GHz': 12,
|
||
'2.472 GHz': 13, '2.484 GHz': 14 }
|
||
try:
|
||
ret = freq_dict[frecuencia]
|
||
except KeyError:
|
||
print "No se puede determinar el canal para la frecuencia: " + str(frecuencia)
|
||
return ret
|
||
|
||
def get_link_quality(red):
|
||
""" Obtiene la calidad del enlace desde la salida iwlist.
|
||
"""
|
||
try:
|
||
[(strength, max_strength)] = strength_pattern.findall(red)
|
||
except ValueError:
|
||
(strength, max_strength) = (None, None)
|
||
if strength in ['', None]:
|
||
try:
|
||
[(strength, max_strength)] = altstrength_pattern.findall(red)
|
||
except ValueError:
|
||
# Si el patrón no encuentra coincidencias
|
||
# retornamos 101
|
||
return 101
|
||
if strength not in ['', None] and max_strength:
|
||
#print "strength,max",strength,max_strength
|
||
return (100 * int(strength) // int(max_strength))
|
||
elif strength not in ["", None]:
|
||
#print "strength,max",strength,max_strength
|
||
return int(strength)
|
||
else:
|
||
#print "strength,max",strength,max_strength
|
||
return None
|
||
|
||
def ParseAccessPoint(red):
|
||
""" Examina una red wifi desde la salida de iwlist.
|
||
Parámetros:
|
||
red -- cadena que contiene la identificación de la red.
|
||
Devuelve:
|
||
Un diccionario que contiene las propiedades de la red wifi
|
||
examinada.
|
||
"""
|
||
ap = {}
|
||
ap['essid'] = EjecutaRegex(essid_pattern, red)
|
||
try:
|
||
ap['essid'] = to_unicode(ap['essid'])
|
||
except (UnicodeDecodeError, UnicodeEncodeError):
|
||
print 'Problema Unicode con el essid de la red actual, ignorando!!'
|
||
return None
|
||
if ap['essid'] in ['Hidden', '<hidden>', "", None]:
|
||
print 'hidden'
|
||
ap['oculta'] = True
|
||
ap['essid'] = "<hidden>"
|
||
else:
|
||
ap['oculta'] = False
|
||
# Canal - Para interfaces que no tienen un número de canal,
|
||
# convertir la frecuencia.
|
||
ap['canal'] = EjecutaRegex(channel_pattern, red)
|
||
if ap['canal'] == None:
|
||
freq = EjecutaRegex(freq_pattern, red)
|
||
ap['canal'] = FrecuenciaACanal(freq)
|
||
# BSSID
|
||
ap['bssid'] = EjecutaRegex(ap_mac_pattern, red)
|
||
# Calidad del enlace
|
||
# Ajusta strength a -1 si no se encuentra calidad
|
||
ap['calidad'] = get_link_quality(red)
|
||
if ap['calidad'] is None:
|
||
ap['calidad'] = -1
|
||
# Signal Strength (only used if user doesn't want link
|
||
# quality displayed or it isn't found)
|
||
if EjecutaRegex(signaldbm_pattern, red):
|
||
ap['intensidad'] = EjecutaRegex(signaldbm_pattern, red)
|
||
return ap
|
||
|
||
def getWirelessInterfaces():
|
||
""" Extract wireless device names from /proc/net/wireless.
|
||
|
||
Returns empty list if no devices are present.
|
||
|
||
>>> getWirelessInterfaces()
|
||
['eth1', 'wifi0']
|
||
|
||
"""
|
||
device = re.compile('[a-z]{2,}[0-9]*:')
|
||
ifnames = []
|
||
|
||
fp = open('/proc/net/wireless', 'r')
|
||
for line in fp:
|
||
try:
|
||
# append matching pattern, without the trailing colon
|
||
ifnames.append(device.search(line).group()[:-1])
|
||
except AttributeError:
|
||
pass
|
||
|
||
return ifnames
|
||
|
||
def ObtieneRedes(interface):
|
||
""" Obtiene una lista de redes wifi disponibles. La usamos para
|
||
obtener via iwlist datos de las redes disponibles. De momento
|
||
lo usamos para obtener los valores del calidad e intensidad,
|
||
ya que la librería pythonwifi no parece dar los valores correctos
|
||
de estos parámetros.
|
||
|
||
Parámetros:
|
||
interface -- Interfaz sobre la que escanear
|
||
Devuelve:
|
||
Diccionario cuyas claves son ls bssids y cada elemento
|
||
es otro diccionario cuyas claves con las características
|
||
recogidas por iwlist
|
||
"""
|
||
|
||
#Si hostapd está corriendo iwlist scan no funciona:
|
||
Popen(["invoke-rc.d","hostapd","stop"]).wait()
|
||
time.sleep(2.0)
|
||
Popen(["ifconfig",interface,"up"]).wait()
|
||
|
||
cmd = 'iwlist ' + interface + ' scan'
|
||
resultado = Ejecuta(cmd)
|
||
# Divide las redes, utilizando Cell como punto de división
|
||
# de esta forma podemos mirar una red cada vez.
|
||
# Los espacios alrededor de ' Cell ' son para evitar el caso
|
||
# de que alguien tenga un essid llamado Cell...
|
||
redes = resultado.split( ' Cell ' )
|
||
# An array for the access points
|
||
access_points = []
|
||
access_points = {}
|
||
for red in redes:
|
||
# Solo usa secciones donde haya un ESSID.
|
||
if 'ESSID:' in red:
|
||
# Añadir la red a la lista de redes
|
||
entry = ParseAccessPoint(red)
|
||
if entry is not None:
|
||
# Normalmente solo tenemos bssids duplicados con redes
|
||
# ocultas. Solo nos fijamos en el essid real, para
|
||
# que esté en la lista.
|
||
if (entry['bssid'] not in access_points or not entry['oculta']):
|
||
access_points[entry['bssid']] = entry
|
||
return access_points
|
||
|
||
if __name__ == "__main__":
|
||
datos_redes = ObtieneRedes('eth1')
|
||
print datos_redes
|
||
wifi-ltsp/trunk/transformaArchivos.py | ||
---|---|---|
#!/usr/bin/python
|
||
# -*- coding: utf-8 -*-
|
||
# Project: wifi-ltsp
|
||
# Module: transformaArchivos.py
|
||
# Purpose: Genera archivo de macs con horarios desde Rayuela y Ldap
|
||
# Language: Python 2.5
|
||
# Date: 03-Feb-2011.
|
||
# Ver: 07-Feb-2011.
|
||
# Author: Francisco Mora Sánchez
|
||
# Copyright: 2011 - Francisco Mora Sánchez <adminies.maestrojuancalero@edu.juntaextremadura.net>
|
||
#
|
||
# wifi-ltsp is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 3 of the License, or
|
||
# (at your option) any later version.
|
||
# Script2 is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with wifi-ltsp. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
""" Programa para generar los archivos necesarios para permitir
|
||
que los portátiles de los alumnos puedan unirse al punto de acceso
|
||
hostapd del profesor, según el horario del propio profesor, y los
|
||
alumnos que tienen clase con él a esa hora.
|
||
|
||
Partiremos de los archivos de datos generados por Rayuela, el formato
|
||
de estos archivos es: por cada centro hay un directorio con cinco archivos
|
||
uno por cada día de la semana, llamados Lunes.txt, Martes.txt, Miercoles.txt,
|
||
Jueves.txt y Viernes.txt. Cada uno de estos archivos de texto contienen
|
||
la siguiente información:
|
||
|
||
D.N.I. del docente|N.I.A. del alumno|Hora de inicio|Hora de fin
|
||
08848648L|3251023|815|870|
|
||
08848648L|3383767|815|870|
|
||
08848648L|3383770|815|870|
|
||
|
||
la primera línea indica la estructura y a partir de ésta están los datos
|
||
que son: dni del profesor, nie del alumno y horas de inicio y fin expresadas
|
||
como minutos transcurridos desde las 00:00 horas.
|
||
|
||
Los ficheros que se generan, deben copiarse al directorio de destino
|
||
especificado como parámetro, y que en caso de no darse será por defecto
|
||
"/var/www/wifi/(lunes.txt|martex.txt|miercoles.txt|jueves.txt|viernes.txt)"
|
||
si la ruta no existe, ésta se creará. Para escribir en el destino debemos
|
||
tener los privilegios adecuados.
|
||
|
||
Los archivos que generaremos, tendrán el mismo nombre, sin mayúsculas, pero
|
||
el formato será el siguiente:
|
||
|
||
login_profesor|mac_alumno|inicio|fin|
|
||
|
||
no tenemos línea descriptora de estructura, y los datos se obtienen de
|
||
realizar consulta al directorio ldap del centro, para lo cual es necesario
|
||
que tengamos instalado el paquete python-ldap, además de python, claro está.
|
||
El dato de login_profesor es directo en la consulta a ldap, así como la
|
||
generación de las horas y minutos, pero el dato de mac_alumno, se realiza
|
||
consultando ldap para obtener el login del alumno, que concuerda con el
|
||
nombre del portátil asignado al alumno. A partir de este dato accederemos
|
||
a la información recogida por puppet de cada ordenador, que se encuentra
|
||
en /var/lib/puppet/yaml/node/(login_del_alumno.dominiodelcentro).yaml,
|
||
para obtener la mac de la interfaz wifi asociada a ese portátil. Las
|
||
líneas importantes son: macaddress_wlan0 o macaddress_eth1 que se
|
||
establece en algunos modelos de portátiles.
|
||
|
||
Uso: crearemos una carpeta donde copiaremos este programa y además
|
||
pondremos los txts obtenidos por Rayuela, ejecutaremos el script pasando
|
||
como parámetros el lugar donde están los archivos con el parámetro
|
||
--datosrayuela rutarayuela, y tambien el lugar donde queremos depositar los
|
||
archivos generados, con el parámetros --datosservidor rutaservidor.
|
||
Si --datosrayuela no se establece, asumiremos el directorio actual, si
|
||
--datosservidor no está establecido, se establecerá internamente en
|
||
/var/www/wifi, creando la estructura de directorios mencionada si es que
|
||
no existe, además comprobaremos que disponemos de privilegios para escribir
|
||
en el directorio de destino.
|
||
|
||
Francisco Mora Sánchez
|
||
IES Maestro Juan Calero
|
||
adminies.maestrojuancalero@edu.juntaextremadura.net
|
||
|
||
|
||
"""
|
||
|
||
import sys,os,re
|
||
import ldap
|
||
|
||
# Expresiones Regulares.
|
||
_re_mode = (re.I | re.M | re.S)
|
||
macwlan0_pattern = re.compile('.*macaddress_wlan0: (.*?)\n', _re_mode)
|
||
maceth1_pattern = re.compile('.*macaddress_eth1: (.*?)\n', _re_mode)
|
||
|
||
|
||
def EjecutaRegex(regex, cadena):
|
||
""" ejecuta búsqueda de expresión regular en una cadena """
|
||
m = regex.search(cadena)
|
||
if m:
|
||
return m.groups()[0]
|
||
else:
|
||
return None
|
||
|
||
|
||
def lee_parametros(lista,params):
|
||
"""Funcion que crea un diccionario para leer el valor de los
|
||
parametros que se pasan en la linea de comandos."""
|
||
for i in range(1,len(lista)):
|
||
if lista[i][:2] == "--":
|
||
#veamos si tiene valor
|
||
if i+1 < len(lista) and lista[i+1] <> "--":
|
||
#estamos en un parametro y valor
|
||
params[lista[i][2:]] = lista[i+1]
|
||
|
||
def dameDatosLineaRayuela(linea):
|
||
"""Funcion que trocea la linea de datos de rayuela y
|
||
devuelve un diccionario cuyas claves son login_profesor
|
||
login_alumno, inicio y final
|
||
"""
|
||
datos = linea.split("|")
|
||
return { "dni_profesor" : datos[0], "nie_alumno" : datos[1], "inicio" : datos[2], "final" : datos[3]}
|
||
|
||
def consultaLdap(identificador, contra):
|
||
"""Función que consulta el servidor ldap, con el atributo
|
||
employeeNumber. Devuelve el login asociado al profesor o al alumno
|
||
"""
|
||
try:
|
||
l = ldap.open("ldap")
|
||
l.protocol_version = ldap.VERSION3
|
||
usuario = 'cn=Admin,ou=People,dc=instituto,dc=extremadura,dc=es'
|
||
l.simple_bind(usuario, contra)
|
||
|
||
except ldap.LDAPError, e:
|
||
print e
|
||
return "ERRORLDAP"
|
||
|
||
base_dn='ou=People,dc=instituto,dc=extremadura,dc=es'
|
||
searchFilter = '(employeeNumber='+identificador+')'
|
||
searchScope = ldap.SCOPE_SUBTREE
|
||
|
||
retrieveAttributes = ['uid']
|
||
|
||
try:
|
||
ldap_result_id = l.search(base_dn, searchScope, searchFilter, retrieveAttributes)
|
||
result_type, result_data = l.result(ldap_result_id, 0)
|
||
if len(result_data)==0:
|
||
#print "la búsqueda no da ningún resultado"
|
||
return "NO ENCONTRADO"
|
||
elif len(result_data)>1:
|
||
#print "La búsqueda da más de un resultado"
|
||
resultado= result_data[0]
|
||
else:
|
||
resultado=result_data[0]
|
||
|
||
#print resultado[1]['uid'][0]
|
||
except ldap.LDAPError, e:
|
||
print e
|
||
print "ERRORLDAP"
|
||
|
||
return resultado[1]['uid'][0]
|
||
|
||
def obtenerMac(login_alumno, archivosYaml, datosyaml):
|
||
"""Función que dado un login de alumno, buscará en el archivo yaml
|
||
de puppet asociado a ese login de alumno, la cadena macaddress_wlan0,
|
||
o bien macaddress_eth1 en caso que no exista la primera. Esta función
|
||
quizá se deba testear bien.
|
||
Tenemos disponible la lista archivosYaml con todos los archivos yaml
|
||
de puppet, incluyendo sus rutas...
|
||
"""
|
||
#Primero buscamos el archivo en cuestion, tendrá el login_alumno mas
|
||
#un punto, dominio, punto y terminación yaml, busquemos el patrón con dos puntos
|
||
#ya que suele haber archivos fantasmas con el nombre solamente.
|
||
for a in archivosYaml:
|
||
if a.count(".") == 2:
|
||
#Estamos en un patrón de archivo correcto.
|
||
pos = a.find(".")
|
||
sufijo = a[pos:]
|
||
break
|
||
|
||
archivoDatosYaml = login_alumno + sufijo
|
||
try:
|
||
filearchivoDatosYaml = open(os.path.join(datosyaml,archivoDatosYaml), "r")
|
||
except:
|
||
pass
|
||
return "99:99:99:99:99:99"
|
||
contenidoyaml = filearchivoDatosYaml.read()
|
||
filearchivoDatosYaml.close()
|
||
#print contenidoyaml
|
||
mac = EjecutaRegex(macwlan0_pattern, contenidoyaml)
|
||
if mac == None:
|
||
mac = EjecutaRegex(maceth1_pattern, contenidoyaml)
|
||
#print mac
|
||
if mac == None:
|
||
mac = "99:99:99:99:99:99"
|
||
return mac
|
||
|
||
def transformaHora(datohora):
|
||
"""Función que pasado un parámetro numérico que almacena los minutos
|
||
desde las 00:00.
|
||
Devuelve una cadena en la forma "08:35", con la hora y los minutos.
|
||
"""
|
||
hora = datohora // 60
|
||
minutos = datohora % 60
|
||
return "%02d%02d" % (hora,minutos)
|
||
|
||
def transformaArchivos(datosrayuela, datosservidor, datosyaml, contra, debug = False):
|
||
#Comprobemos la existencia del directorio de datos de Rayuela
|
||
if not os.path.exists(datosrayuela):
|
||
if debug:
|
||
print "Directorio para datos de rayuela",datosrayuela,"no existe, abortando ejecución..."
|
||
return 1
|
||
|
||
#Comprobemos que sea un directorio
|
||
if not os.path.isdir(datosrayuela):
|
||
if debug:
|
||
print "Directorio para datos de rayuela",datosrayuela,"no es un directorio, abortando ejecución..."
|
||
return 2
|
||
|
||
#Comprobemos que tengamos permisos de apertura y lectura de archivos
|
||
if os.path.isdir(datosrayuela):
|
||
try:
|
||
archivosRayuela = os.listdir(datosrayuela)
|
||
except:
|
||
if debug:
|
||
print "Directorio para datos de rayuela",datosrayuela,"problemas de permisos en carpeta, abortando ejecución..."
|
||
return 3
|
||
|
||
#Comprobemos que existe el directorio de destino
|
||
if not os.path.exists(datosservidor):
|
||
#No existe directorio de destino, debemos crearlo
|
||
if debug:
|
||
print "No existe directorio de destino en servidor",datosservidor,"se intentará crear directorio..."
|
||
try:
|
||
os.makedirs(datosservidor)
|
||
except OSError:
|
||
if debug:
|
||
print "Hay algún problema con la creación del directorio de destino, abortando ejecución..."
|
||
return 4
|
||
|
||
#Comprobemos que tenemos permisos de escritura
|
||
if os.path.exists(datosservidor):
|
||
if not os.access(datosservidor, os.W_OK):
|
||
if debug:
|
||
print "Hay algún problema de permisos para la creación de archivos en el directorio de destino del servidor, abortando ejecución..."
|
||
return 5
|
||
|
||
#Comprobemos la existencia del directorio de datos yaml de puppet
|
||
if not os.path.exists(datosyaml):
|
||
if debug:
|
||
print "Directorio para datos yaml de puppet",datosyaml,"no existe, abortando ejecución..."
|
||
return 6
|
||
|
||
#Comprobemos que sea un directorio
|
||
if not os.path.isdir(datosyaml):
|
||
if debug:
|
||
print "Directorio para datos yaml de puppet",datosyaml,"no es un directorio, abortando ejecución..."
|
||
return 7
|
||
|
||
#Comprobemos que tengamos permisos de apertura y lectura de archivos
|
||
if os.path.isdir(datosyaml):
|
||
try:
|
||
#archivosYaml = glob.glob(os.path.join(params["datosyaml"],"*.*.yaml"))
|
||
archivosYaml = os.listdir(datosyaml)
|
||
except:
|
||
if debug:
|
||
print "Directorio para datos yaml de puppet",datosyaml,"problemas de permisos en directorio, abortando ejecución..."
|
||
return 8
|
||
|
||
#Limpiemos las listas de archivos
|
||
#Tengamos en cuenta que los archivos entregados por rayuela pueden contener distinto patron en mayusculas y minusculas
|
||
dicArchivosRayuela = {"lunes.txt":"","martes.txt":"","miercoles.txt":"","jueves.txt":"","viernes.txt":""}
|
||
for archivoRayuela in archivosRayuela:
|
||
if archivoRayuela.lower() in dicArchivosRayuela.keys():
|
||
dicArchivosRayuela[archivoRayuela.lower()] = archivoRayuela
|
||
|
||
archivosYaml = [ archivo for archivo in archivosYaml if archivo[-5:] == ".yaml"]
|
||
#print archivosRayuela
|
||
#print archivosYaml
|
||
#Para evitar consultar al servidor ldap varias veces para un mismo dni o nie crearemos
|
||
#dos diccionarios, uno para profesores y otro para alumnos con los datos que
|
||
#recuperaremos del servidor ldap, además otro con los logins de alumnos y
|
||
#las macs
|
||
#profesores = { "dni" : "login_profesor", ... }
|
||
#alumnos = { "nie" : "login_alumno", ... }
|
||
#macs = { "login_alumno" : "mac", ... }
|
||
profesores = {}
|
||
alumnos = {}
|
||
macs = {}
|
||
#Procesemos cada archivo de Rayuela
|
||
for archivoRayuela in dicArchivosRayuela.keys():
|
||
if debug:
|
||
print "Procesando archivo",os.path.join(datosrayuela,dicArchivosRayuela[archivoRayuela])
|
||
filearchivoRayuela = open(os.path.join(datosrayuela,dicArchivosRayuela[archivoRayuela]), 'r')
|
||
archivoServidor = os.path.join(datosservidor,archivoRayuela)
|
||
if debug:
|
||
print "Generando archivo",archivoServidor
|
||
filearchivoServidor = open(archivoServidor, 'w')
|
||
while True:
|
||
linea = filearchivoRayuela.readline()
|
||
if not linea:
|
||
break
|
||
if not linea[:1].isdigit():
|
||
continue
|
||
#Procesemos cada linea de Rayuela
|
||
#datosLineaRayuela es un diccionario cuyas claves son dni_profesor, nie_alumno, inicio, final
|
||
datosLineaRayuela = dameDatosLineaRayuela(linea)
|
||
datosLineaServidor = ""
|
||
#Consultemos el login del profesor en ldap por su dni y el nie del alumno
|
||
#comprobando que no lo hemos encontrado previamente
|
||
dni_profesor=datosLineaRayuela["dni_profesor"]
|
||
if profesores.has_key(dni_profesor):
|
||
login_profesor = profesores[dni_profesor]
|
||
#if debug:
|
||
# print "Nooooo se consulta a ldap, profesor dni",datosLineaRayuela["dni_profesor"],"pertenece a",login_profesor
|
||
else:
|
||
login_profesor = consultaLdap(dni_profesor, contra)
|
||
if login_profesor=="NO ENCONTRADO":
|
||
login_profesor = consultaLdap(dni_profesor[1:], contra)
|
||
profesores[dni_profesor] = login_profesor
|
||
if debug:
|
||
print "Se consulta a ldap, profesor dni",datosLineaRayuela["dni_profesor"],"pertenece a",login_profesor
|
||
if alumnos.has_key(datosLineaRayuela["nie_alumno"]):
|
||
login_alumno = alumnos[datosLineaRayuela["nie_alumno"]]
|
||
#if debug:
|
||
# print "Nooooo se consulta a ldap, alumno nie",datosLineaRayuela["nie_alumno"],"pertenece a",login_alumno
|
||
else:
|
||
login_alumno = consultaLdap(datosLineaRayuela["nie_alumno"], contra)
|
||
alumnos[datosLineaRayuela["nie_alumno"]] = login_alumno
|
||
if debug:
|
||
print "Se consulta a ldap, alumno nie",datosLineaRayuela["nie_alumno"],"pertenece a",login_alumno
|
||
|
||
if macs.has_key(login_alumno):
|
||
mac_alumno = macs[login_alumno]
|
||
#if debug:
|
||
# print "Nooooo se consultan datos yaml, alumno login",login_alumno,"tiene mac",mac_alumno
|
||
else:
|
||
mac_alumno = obtenerMac(login_alumno, archivosYaml, datosyaml)
|
||
#mac_alumno = obtenerMac("dmoral01", archivosYaml, datosyaml)
|
||
macs[login_alumno] = mac_alumno
|
||
if debug:
|
||
print "Se consultan datos yaml, alumno login",login_alumno,"tiene mac",mac_alumno
|
||
inicio = transformaHora(int(datosLineaRayuela["inicio"]))
|
||
final = transformaHora(int(datosLineaRayuela["final"]))
|
||
datosLineaServidor = login_profesor+"|"+mac_alumno+"|"+str(inicio)+"|"+str(final)+"|"+"\n"
|
||
#datosLineaServidor = login_profesor+"|"+mac_alumno+"|"+datosLineaRayuela["inicio"]+"|"+datosLineaRayuela["final"]+"|"+"\n"
|
||
if debug:
|
||
print datosLineaServidor
|
||
filearchivoServidor.write(datosLineaServidor)
|
||
filearchivoRayuela.close()
|
||
filearchivoServidor.close()
|
||
return 0
|
||
|
||
if __name__ == '__main__':
|
||
params = {}
|
||
lista = sys.argv
|
||
lee_parametros(lista,params)
|
||
#comprobaremos las combinaciones de parametros en linea de comandos
|
||
if len(lista) == 2 and lista[1] == "--help":
|
||
print 'uso: ./transformaArchivos.py [--datosrayuela rutadatosrayuela] [--datosservidor rutadatosservidor] [--datosyaml rutadatosyaml] [--contra contraadminldap]'
|
||
sys.exit(1)
|
||
if not params.has_key("contra"):
|
||
print "No se ha establecido la contraseña del administrador ldap..."
|
||
sys.exit(2)
|
||
if not params.has_key("datosrayuela"):
|
||
print "No se ha establecido la ruta a la carpeta con los datos de rayuela, usando por defecto '"+os.getcwd()+"'"
|
||
params["datosrayuela"] = os.getcwd()
|
||
if not params.has_key("datosservidor"):
|
||
print "No se ha establecido la ruta dónde depositar los archivos generados, usando por defecto '/var/www/wifi'"
|
||
params["datosservidor"] = "/var/www/wifi"
|
||
if not params.has_key("datosyaml"):
|
||
print "No se ha establecido la ruta dónde se encuentran los datos yaml de puppet, usando por defecto '/var/lib/puppet/yaml/node'"
|
||
params["datosyaml"] = "/var/lib/puppet/yaml/node"
|
||
|
||
print
|
||
print "Los valores pasado son los siguientes:"
|
||
print "Directorio de datos de Rayuela:",params["datosrayuela"]
|
||
print "Directorio de datos de para el servidor:",params["datosservidor"]
|
||
print "Directorio de datos yaml de puppet:",params["datosyaml"]
|
||
|
||
resultado = transformaArchivos(params["datosrayuela"], params["datosservidor"], params["datosyaml"], params["contra"], True)
|
||
if resultado > 0:
|
||
print "Se ha producido errores en el procesamiento, código de error",resultado
|
||
else:
|
||
print "Se ha ejecutado correctamente"
|
||
exit(resultado)
|
||
wifi-ltsp/trunk/autoriza-wifi.desktop | ||
---|---|---|
[Desktop Entry]
|
||
Name=Autoriza WiFi Guardias
|
||
Comment=El profesor de guardia puede simular otro profesor del centro
|
||
Exec=autorizaWifiGuardias.py
|
||
Icon=network-wireless
|
||
Terminal=false
|
||
Type=Application
|
||
StartupNotify=true
|
Exportar a: Unified diff
Reordenacion scripts