diff --git a/gestion/ldap_crans.py b/gestion/ldap_crans.py index d455b538..fc9cfd57 100755 --- a/gestion/ldap_crans.py +++ b/gestion/ldap_crans.py @@ -54,14 +54,14 @@ random.seed() # On initialise le g ### Items de la blackliste blacklist_items = { u'bloq' : u'Bloquage total de tout services' , u'virus' : u'Bloquage sur squid', - u'upload' : u'Bloquage total accès extérieur', - u'warez' : u'Bloquage sur squid' } - + u'upload' : u'Bloquage total accès extérieur', + u'warez' : u'Bloquage sur squid' } + ################################################################################## ### Droits possibles droits_possibles = [ u'Nounou', u'Apprenti', u'Modérateur', u'Câbleur', u'Déconnecteur',u'CVSWeb' , u'WebRadio' , u'Imprimeur'] -################################################################################## +################################################################################## ### Variables internes diverses isadm = user_tests.isadm() isdeconnecteur = user_tests.isdeconnecteur() @@ -91,23 +91,23 @@ def mailexist(mail) : """ Vérifie si un mail existe ou non grace à la commande vrfy du serveur mail """ try : - s=smtplib.SMTP(smtpserv) - r = s.vrfy(mail) - s.close() + s=smtplib.SMTP(smtpserv) + r = s.vrfy(mail) + s.close() except : - raise ValueError(u'Serveur de mail injoignable') + raise ValueError(u'Serveur de mail injoignable') if r[0] in [250, 252] : - return True + return True else : - return False + return False def preattr(val) : """ val est : - * un entier - * une chaîne - * une liste avec un seul entier ou chaine + * un entier + * une chaîne + * une liste avec un seul entier ou chaine Retourne [ len(str(val).strip), str(val).strip en utf-8 ] @@ -116,18 +116,18 @@ def preattr(val) : t = type(val) if t==list and len(val)==1 : - return preattr(val[0]) + return preattr(val[0]) elif t==str or t==int : - val = str(val).strip() - # On passe tout en utf-8 pour ne pas avoir de problèmes - # d'accents dans la base - return [ len(val) , unicode(val,'iso-8859-1').encode('utf-8') ] + val = str(val).strip() + # On passe tout en utf-8 pour ne pas avoir de problèmes + # d'accents dans la base + return [ len(val) , unicode(val,'iso-8859-1').encode('utf-8') ] elif t==unicode : - val = val.strip() - return [ len(val) , val.encode('utf-8') ] + val = val.strip() + return [ len(val) , val.encode('utf-8') ] else : - raise TypeError + raise TypeError def is_actif(sanction) : @@ -137,15 +137,15 @@ def is_actif(sanction) : """ bl = sanction.split(',') try : - now = time.time() - debut = time.mktime( time.strptime(bl[0],date_format) ) - if bl[1]=='-' : - fin = now + 1 - else : - fin = time.mktime( time.strptime(bl[1],date_format) ) - return debut < now and fin > now + now = time.time() + debut = time.mktime( time.strptime(bl[0],date_format) ) + if bl[1]=='-' : + fin = now + 1 + else : + fin = time.mktime( time.strptime(bl[1],date_format) ) + return debut < now and fin > now except : - return False + return False def format_mac(mac) : """ @@ -157,13 +157,13 @@ def format_mac(mac) : l, mac = preattr(mac) mac= mac.replace(':','').replace('-','').replace(' ','').lower() if len(mac)!=12 : - raise ValueError(u'Longueur adresse mac incorrecte.') + raise ValueError(u'Longueur adresse mac incorrecte.') for c in mac[:] : - if c not in string.hexdigits : - raise ValueError(u"Caractère interdit '%s' dans adresse mac." % c) + if c not in string.hexdigits : + raise ValueError(u"Caractère interdit '%s' dans adresse mac." % c) if mac=='000000000000' : - raise ValueError(u"MAC nulle interdite\nIl doit être possible de modifier l'adresse de la carte.") - + raise ValueError(u"MAC nulle interdite\nIl doit être possible de modifier l'adresse de la carte.") + # Formatage mac="%s:%s:%s:%s:%s:%s" % ( mac[:2],mac[2:4],mac[4:6], mac[6:8], mac[8:10], mac[10:] ) @@ -184,279 +184,279 @@ class crans_ldap : ### Configuration de la recheche # Dictionnaire de tranformation des champs trans = { 'prénom' : 'prenom' , - 'chambre' : 'chbre', - 'login' : 'mail' , - 'hostname' : 'host', - 'mac' : 'macAddress', - 'ip' : 'ipHostNumber' , - 'telephone' : 'tel' } - + 'chambre' : 'chbre', + 'login' : 'mail' , + 'hostname' : 'host', + 'mac' : 'macAddress', + 'ip' : 'ipHostNumber' , + 'telephone' : 'tel' } + # Champs de recherche pour la recherche automatique auto_search_champs = { 'adherent' : [ 'nom', 'prenom', 'tel', 'mail', 'chbre', 'mailAlias', 'cannonicalAlias' ], \ - 'machine' : [ 'macAddress', 'host', 'ipHostNumber', 'hostAlias'] , - 'club' : [ 'nom', 'chbre' ] } + 'machine' : [ 'macAddress', 'host', 'ipHostNumber', 'hostAlias'] , + 'club' : [ 'nom', 'chbre' ] } # Champs de recherche pour la recherche manuelle (en plus de la recherche auto) non_auto_search_champs = { 'adherent' : [ 'etudes', 'paiement', 'carteEtudiant', 'aid' , 'postalAddress', 'historique' ,'blacklist', 'droits', 'uidNumber', 'uid' ], \ - 'machine' : [ 'mid' , 'ipsec', 'historique', 'blacklist' , 'puissance', 'canal', 'portTCPin', 'portTCPout', 'portUDPin', 'portUDPout' , 'prise' ] , - 'club' : [ 'cid' , 'responsable', 'paiement', 'historique', 'blacklist'] } - + 'machine' : [ 'mid' , 'ipsec', 'historique', 'blacklist' , 'puissance', 'canal', 'portTCPin', 'portTCPout', 'portUDPin', 'portUDPout' , 'prise' ] , + 'club' : [ 'cid' , 'responsable', 'paiement', 'historique', 'blacklist'] } + # Scope des différentes recherches scope = { 'adherent' : 1 , 'machine' : 2 , 'club' : 1 } def __init__(self) : - self.connect() + self.connect() def connect(self): - """ Initialisation des connexion vers le serveur LDAP """ - - def bind(conn,anon_bind=0) : - """ Authentification auprès du serveur ldap """ - nbessais = 0 - ok = False - while not ok: - try: - if anon_bind : - conn.bind_s('','',ldap.AUTH_SIMPLE) - else : - conn.bind_s(ldap_auth_dn,ldap_password,ldap.AUTH_SIMPLE) - ok = True - - except ldap.SERVER_DOWN : - nbessais += 1 - if nbessais > 2: - sys.stderr.write("ERREUR : serveur LDAP injoignable\n") - sys.exit(1) - else: - sleep(0.3) - - def select_conn(methode_base, methode_alternative) : - """ Retoune une fonction qui : - 1) bind sur la connection self.conn si necessaire - 2) fait ce que ferai methode_base - 3) si échoue bind sur la connexion self.rw_conn - 4) fait ce que ferai methode_alternative """ - - def new_methode(*args) : - try : - if not self.__conn_binded : - bind(self.conn,anon_bind) - self.__conn_binded = True - return methode_base(*args) - except ldap.STRONG_AUTH_REQUIRED : - # On a pas les droits necessaires ici - if not self.__rw_conn_binded : - bind(self.rw_conn) - self.__rw_conn_binded = True - return methode_alternative(*args) - - return new_methode - - # Les objets ldap necessaires - self.conn = ldap.initialize(uri) - self.__conn_binded = False - - self.rw_conn = ldap.initialize(rw_uri) - self.__rw_conn_binded = False - - # Modification des méthodes utilisées - self.conn.search_s = select_conn(self.conn.search_s,self.rw_conn.search_s) - self.conn.add_s = select_conn(self.conn.add_s,self.rw_conn.add_s) - self.conn.modify_s = select_conn(self.conn.modify_s,self.rw_conn.modify_s) - self.conn.delete_s = select_conn(self.conn.delete_s,self.rw_conn.delete_s) - + """ Initialisation des connexion vers le serveur LDAP """ + + def bind(conn,anon_bind=0) : + """ Authentification auprès du serveur ldap """ + nbessais = 0 + ok = False + while not ok: + try: + if anon_bind : + conn.bind_s('','',ldap.AUTH_SIMPLE) + else : + conn.bind_s(ldap_auth_dn,ldap_password,ldap.AUTH_SIMPLE) + ok = True + + except ldap.SERVER_DOWN : + nbessais += 1 + if nbessais > 2: + sys.stderr.write("ERREUR : serveur LDAP injoignable\n") + sys.exit(1) + else: + sleep(0.3) + + def select_conn(methode_base, methode_alternative) : + """ Retoune une fonction qui : + 1) bind sur la connection self.conn si necessaire + 2) fait ce que ferai methode_base + 3) si échoue bind sur la connexion self.rw_conn + 4) fait ce que ferai methode_alternative """ + + def new_methode(*args) : + try : + if not self.__conn_binded : + bind(self.conn,anon_bind) + self.__conn_binded = True + return methode_base(*args) + except ldap.STRONG_AUTH_REQUIRED : + # On a pas les droits necessaires ici + if not self.__rw_conn_binded : + bind(self.rw_conn) + self.__rw_conn_binded = True + return methode_alternative(*args) + + return new_methode + + # Les objets ldap necessaires + self.conn = ldap.initialize(uri) + self.__conn_binded = False + + self.rw_conn = ldap.initialize(rw_uri) + self.__rw_conn_binded = False + + # Modification des méthodes utilisées + self.conn.search_s = select_conn(self.conn.search_s,self.rw_conn.search_s) + self.conn.add_s = select_conn(self.conn.add_s,self.rw_conn.add_s) + self.conn.modify_s = select_conn(self.conn.modify_s,self.rw_conn.modify_s) + self.conn.delete_s = select_conn(self.conn.delete_s,self.rw_conn.delete_s) + def exist(self,arg) : - """ - Vérifie l'existence d'une entrée dans la base et que cette entrée - n'appartient pas à l'objet en cours, prend en compte les locks - arg doit être une expression de recherche ldap - Si existence, retourne la liste de dn correspondants - Sinon retourne une liste vide - Exemple : exist('chbre=Z345') vérifie si il y a un adhérent en Z345 - """ - r=[] - - # Premier test : dans les objets déja inscrits - ret = self.conn.search_s(self.base_dn,2,arg) - for res in ret : - # C'est peut être l'objet courant - try : # Si ce n'est pas une classe fille avec l'attribu dn => erreur - if res[0] == self.dn : - continue - except : - pass - r.append(res[0]) - - # Deuxième test : lock ? - ret = self.conn.search_s(self.base_lock,1,arg) - lockid = '%s-%s' % (hostname, os.getpid() ) - for res in ret : - # Lock encore actif ? - l = res[1]['lockid'][0] - if l == lockid : continue - # C'est locké par un autre process que le notre - # il tourne encore ? - try : - if l.split('-')[0] == hostname and os.system('ps %s > /dev/null 2>&1' % l.split('-')[1] ) : - # Il ne tourne plus - self.remove_lock(res[0]) # delock - continue - except : - pass - r.append(res[0]) - - return r - + """ + Vérifie l'existence d'une entrée dans la base et que cette entrée + n'appartient pas à l'objet en cours, prend en compte les locks + arg doit être une expression de recherche ldap + Si existence, retourne la liste de dn correspondants + Sinon retourne une liste vide + Exemple : exist('chbre=Z345') vérifie si il y a un adhérent en Z345 + """ + r=[] + + # Premier test : dans les objets déja inscrits + ret = self.conn.search_s(self.base_dn,2,arg) + for res in ret : + # C'est peut être l'objet courant + try : # Si ce n'est pas une classe fille avec l'attribu dn => erreur + if res[0] == self.dn : + continue + except : + pass + r.append(res[0]) + + # Deuxième test : lock ? + ret = self.conn.search_s(self.base_lock,1,arg) + lockid = '%s-%s' % (hostname, os.getpid() ) + for res in ret : + # Lock encore actif ? + l = res[1]['lockid'][0] + if l == lockid : continue + # C'est locké par un autre process que le notre + # il tourne encore ? + try : + if l.split('-')[0] == hostname and os.system('ps %s > /dev/null 2>&1' % l.split('-')[1] ) : + # Il ne tourne plus + self.remove_lock(res[0]) # delock + continue + except : + pass + r.append(res[0]) + + return r + def lock(self,item,valeur) : - """ Lock un item avec la valeur valeur, les items possibles peuvent être : - aid $ chbre $ mail $ mailAlias $ cannonicalAlias $ - mid $ macAddress $ host $ hostAlias $ ipHostNumber - retourne le dn du lock - """ - - valeur = valeur.encode('utf-8') - - if not valeur : - # On le lock pas un truc vide - return True - - lock_dn = '%s=%s,%s' % ( item, valeur, self.base_lock ) - lockid = '%s-%s' % (hostname, os.getpid() ) - modlist = ldap.modlist.addModlist({ 'objectClass' : 'lock' , - 'lockid' : lockid , - item : valeur } ) - - try : - self.conn.add_s(lock_dn,modlist) - except ldap.ALREADY_EXISTS : - # Pas de chance, le lock est déja pris - try : - res = self.conn.search_s(lock_dn,2,'objectClass=lock')[0] - l = res[1]['lockid'][0] - except : l = '' - if l != lockid : - # C'est locké par un autre process que le notre - # il tourne encore ? - try : - if l.split('-')[0] == hostname and os.system('ps %s > /dev/null 2>&1' % l.split('-')[1] ) : - # Il ne tourne plus - self.remove_lock(res[0]) # delock - return self.lock(item,valeur) # relock - except : - pass - raise EnvironmentError(u'Objet (%s=%s) locké, patienter.' % (item, valeur), l) - - return lock_dn - + """ Lock un item avec la valeur valeur, les items possibles peuvent être : + aid $ chbre $ mail $ mailAlias $ cannonicalAlias $ + mid $ macAddress $ host $ hostAlias $ ipHostNumber + retourne le dn du lock + """ + + valeur = valeur.encode('utf-8') + + if not valeur : + # On le lock pas un truc vide + return True + + lock_dn = '%s=%s,%s' % ( item, valeur, self.base_lock ) + lockid = '%s-%s' % (hostname, os.getpid() ) + modlist = ldap.modlist.addModlist({ 'objectClass' : 'lock' , + 'lockid' : lockid , + item : valeur } ) + + try : + self.conn.add_s(lock_dn,modlist) + except ldap.ALREADY_EXISTS : + # Pas de chance, le lock est déja pris + try : + res = self.conn.search_s(lock_dn,2,'objectClass=lock')[0] + l = res[1]['lockid'][0] + except : l = '' + if l != lockid : + # C'est locké par un autre process que le notre + # il tourne encore ? + try : + if l.split('-')[0] == hostname and os.system('ps %s > /dev/null 2>&1' % l.split('-')[1] ) : + # Il ne tourne plus + self.remove_lock(res[0]) # delock + return self.lock(item,valeur) # relock + except : + pass + raise EnvironmentError(u'Objet (%s=%s) locké, patienter.' % (item, valeur), l) + + return lock_dn + def remove_lock(self,lockdn) : - """ Destruction d'un lock - Destruction de tous les locks si lockdn=*""" - # Mettre des verifs ? - if lockdn!='*' : - self.conn.delete_s(lockdn) - else : - locks = self.list_locks() - for l in locks : - self.conn.delete_s(l[0]) + """ Destruction d'un lock + Destruction de tous les locks si lockdn=*""" + # Mettre des verifs ? + if lockdn!='*' : + self.conn.delete_s(lockdn) + else : + locks = self.list_locks() + for l in locks : + self.conn.delete_s(l[0]) def list_locks(self) : - """ Liste les locks """ - return self.conn.search_s(self.base_lock,1,'objectClass=lock') - + """ Liste les locks """ + return self.conn.search_s(self.base_lock,1,'objectClass=lock') + def services_to_restart(self,new=None,args=[]) : - """ Si new = None retourne la liste des services à redémarrer - Si new est founi et ne comence pas par - ajoute le service à la liste - avec les arguments args (args doit être une liste). - Si new est founi et ne comence par - supprime le service de la liste - """ - - if new and new[0] == '-' : - serv_dn = 'cn=%s,%s' % ( new[1:], self.base_services ) - try : self.conn.delete_s(serv_dn) - except : pass - # Si n'existe pas => Erreur mais le résultat est la. - return - - # Quels services sont déjà à redémarrer ? - serv = {} # { service : [ arguments ] } - for s in self.conn.search_s(self.base_services,1,'objectClass=service') : - s=s[1] - serv[s['cn'][0]] = s.get('args',[]) - - if not new : return serv - - serv_dn = 'cn=%s,%s' % ( new, self.base_services ) - - # Petite fonction à appliquer aux arguments - def tr(arg) : - return preattr(arg)[1] - args=map(tr,args) + """ Si new = None retourne la liste des services à redémarrer + Si new est founi et ne comence pas par - ajoute le service à la liste + avec les arguments args (args doit être une liste). + Si new est founi et ne comence par - supprime le service de la liste + """ + + if new and new[0] == '-' : + serv_dn = 'cn=%s,%s' % ( new[1:], self.base_services ) + try : self.conn.delete_s(serv_dn) + except : pass + # Si n'existe pas => Erreur mais le résultat est la. + return + + # Quels services sont déjà à redémarrer ? + serv = {} # { service : [ arguments ] } + for s in self.conn.search_s(self.base_services,1,'objectClass=service') : + s=s[1] + serv[s['cn'][0]] = s.get('args',[]) + + if not new : return serv + + serv_dn = 'cn=%s,%s' % ( new, self.base_services ) + + # Petite fonction à appliquer aux arguments + def tr(arg) : + return preattr(arg)[1] + args=map(tr,args) - if new in serv.keys() : - new_args = [] - for arg in args : - if arg not in serv[new] : - new_args.append(arg) - if new_args : - modlist = ldap.modlist.modifyModlist({ 'args' : serv[new] }, { 'args' : serv[new] + new_args }) - try : - self.conn.modify_s(serv_dn,modlist) - except ldap.TYPE_OR_VALUE_EXISTS : - # Pas grave - pass - # else rien à faire - else : - modlist = ldap.modlist.addModlist({ 'objectClass' : 'service' , - 'cn' : new , - 'args' : args } ) - try : - self.conn.add_s(serv_dn,modlist) - except ldap.ALREADY_EXISTS : - # Existe déja => rien à faire - pass - + if new in serv.keys() : + new_args = [] + for arg in args : + if arg not in serv[new] : + new_args.append(arg) + if new_args : + modlist = ldap.modlist.modifyModlist({ 'args' : serv[new] }, { 'args' : serv[new] + new_args }) + try : + self.conn.modify_s(serv_dn,modlist) + except ldap.TYPE_OR_VALUE_EXISTS : + # Pas grave + pass + # else rien à faire + else : + modlist = ldap.modlist.addModlist({ 'objectClass' : 'service' , + 'cn' : new , + 'args' : args } ) + try : + self.conn.add_s(serv_dn,modlist) + except ldap.ALREADY_EXISTS : + # Existe déja => rien à faire + pass + def search(self,expression,mode='') : - """ - Recherche dans la base LDAP, expression est une chaîne : - une expression : champ1=expr1 champ2=expr2 champ3!=expr3.... - soit un seul terme, dans ce cas cherche sur les champs de auto_search_champs - Si mode ='w' les instances crées seront en mode d'écriture - """ - - if type(expression)==str : - # Transformation de l'expression en utf-8 - expression = unicode(expression,'iso-8859-15').encode('utf-8') - elif type(expression)==unicode : - expression = expression.encode('utf-8') - else : - raise TypeError(u'Chaine attendue') - - if not expression : - return [] - - # Il faut un filtre par type d'objet de la base - filtres = self.auto_search_champs.keys() - result={'adherent' : [], 'machine' : [], 'club' : []} - - # Fonction utile - def build_filtre(champ,expr,neg=0) : - """ Retourne une chaine pour recherche dans la base LDAP - du style (champ=expr) en adaptant les valeurs de expr au champ - si neg = 1 : retourne le négatif : (!(champ=expr))""" - el = '' - if champ in [ 'host', 'hostAlias' ] : - if expr[-1] == '*' : - el = '(%s=%s)' % (champ, expr) - elif expr.find('.')==-1 : - el = '(%s=%s.*)' % ( champ, expr) - else : - el = '(%s=%s*)' % ( champ, expr) - elif champ == 'macAddress' : - # Formatage adresse mac - try : el = '(macAddress=%s)' % format_mac(expr) - except : return '' - elif champ == 'paiement' and expr=='ok' : - # Paiement donnant droit à une connexion maintenant ? + """ + Recherche dans la base LDAP, expression est une chaîne : + une expression : champ1=expr1 champ2=expr2 champ3!=expr3.... + soit un seul terme, dans ce cas cherche sur les champs de auto_search_champs + Si mode ='w' les instances crées seront en mode d'écriture + """ + + if type(expression)==str : + # Transformation de l'expression en utf-8 + expression = unicode(expression,'iso-8859-15').encode('utf-8') + elif type(expression)==unicode : + expression = expression.encode('utf-8') + else : + raise TypeError(u'Chaine attendue') + + if not expression : + return [] + + # Il faut un filtre par type d'objet de la base + filtres = self.auto_search_champs.keys() + result={'adherent' : [], 'machine' : [], 'club' : []} + + # Fonction utile + def build_filtre(champ,expr,neg=0) : + """ Retourne une chaine pour recherche dans la base LDAP + du style (champ=expr) en adaptant les valeurs de expr au champ + si neg = 1 : retourne le négatif : (!(champ=expr))""" + el = '' + if champ in [ 'host', 'hostAlias' ] : + if expr[-1] == '*' : + el = '(%s=%s)' % (champ, expr) + elif expr.find('.')==-1 : + el = '(%s=%s.*)' % ( champ, expr) + else : + el = '(%s=%s*)' % ( champ, expr) + elif champ == 'macAddress' : + # Formatage adresse mac + try : el = '(macAddress=%s)' % format_mac(expr) + except : return '' + elif champ == 'paiement' and expr=='ok' : + # Paiement donnant droit à une connexion maintenant ? # Deux cas : # - classique : résident sur le campus, il doit avoir payé pour # l'année en cours ou pour l'année précédente @@ -470,145 +470,145 @@ class crans_ldap : # # Cas wifi elwifi = "(&(chbre=EXT)(|%s))" % ("(historique=%s * : inscription)"*4) % tuple(map(lambda i: time.strftime(date_format.split(" ")[0],time.localtime(time.time()-60*60*24*i)),[0,1,2,3])) - if localtime()[1] == 9 : - # Pour septembre paiement année précédente ok - el = "(|(paiement=%s)(paiement=%s)%s)" % (int(ann_scol), int(ann_scol)-1, elwifi) - else : - el = "(|(paiement=%s)%s)" % (int(ann_scol), elwifi) + if localtime()[1] == 9 : + # Pour septembre paiement année précédente ok + el = "(|(paiement=%s)(paiement=%s)%s)" % (int(ann_scol), int(ann_scol)-1, elwifi) + else : + el = "(|(paiement=%s)%s)" % (int(ann_scol), elwifi) # Doit-on bloquer en cas de manque de la carte d'etudiant ? if config.bl_carte_et_definitif: el = "(&(|(carteEtudiant=%s)(objectClass=club))%s)" % (int(ann_scol), el) - else : - # Cas général - el = '(%s=%s)' % (champ, expr) - if neg : el = '(!%s)' % el - return el - - if expression.find('=')!=-1 : - #### Recherche avec conditions explicites - ## Construction des filtres - - # initialisation - filtre={} - filtre_cond={} # Stokage si filtre avec condition (ne comporte pas que des *) - filtre_tout=1 # Passse à 0 si au moins une condition - - for i in filtres : - filtre[i]='(&' - filtre_cond[i] = 0 - conds = expression.split('&') - - # Test de l'expression de recherche et classement par filtres - for cond in conds : - neg = 0 - try : - champ, expr = cond.strip().split('=') - if champ[-1] == '!' : - # Négation pour se champ - champ = champ[:-1] - neg = 1 - except : - raise ValueError(u'Syntaxe de recherche invalide.') - - # transformation de certains champs - champ = self.trans.get(champ,champ) + else : + # Cas général + el = '(%s=%s)' % (champ, expr) + if neg : el = '(!%s)' % el + return el + + if expression.find('=')!=-1 : + #### Recherche avec conditions explicites + ## Construction des filtres + + # initialisation + filtre={} + filtre_cond={} # Stokage si filtre avec condition (ne comporte pas que des *) + filtre_tout=1 # Passse à 0 si au moins une condition + + for i in filtres : + filtre[i]='(&' + filtre_cond[i] = 0 + conds = expression.split('&') + + # Test de l'expression de recherche et classement par filtres + for cond in conds : + neg = 0 + try : + champ, expr = cond.strip().split('=') + if champ[-1] == '!' : + # Négation pour se champ + champ = champ[:-1] + neg = 1 + except : + raise ValueError(u'Syntaxe de recherche invalide.') + + # transformation de certains champs + champ = self.trans.get(champ,champ) - if expr=='' : expr='*' - - ok = 0 - - # Construction du filtre - for i in filtres : - if champ in self.auto_search_champs[i] + self.non_auto_search_champs[i] : - filtre[i] += build_filtre(champ,expr,neg) - ok = 1 - if expr!='*' or neg : - filtre_cond[i] = 1 - filtre_tout=0 - if not ok : - raise ValueError(u'Champ de recherche inconnu (%s)'% champ ) - - ## Recherche avec chacun des filtres - r={} # contiendra les réponses par filtre - for i in filtres : - if (filtre_tout and filtre[i]!='(&' ) or filtre_cond[i] : - # Filtre valide - #filtre[i] += ')' - filtre[i] += '(objectClass=%s))' % i - r[i] = self.conn.search_s(self.base_dn,self.scope[i],filtre[i]) - else : - r[i] = None - - ## On a alors une liste de résultats - ## r = { categorie1 : [ (result1), (result2), ...] , ... } + if expr=='' : expr='*' + + ok = 0 + + # Construction du filtre + for i in filtres : + if champ in self.auto_search_champs[i] + self.non_auto_search_champs[i] : + filtre[i] += build_filtre(champ,expr,neg) + ok = 1 + if expr!='*' or neg : + filtre_cond[i] = 1 + filtre_tout=0 + if not ok : + raise ValueError(u'Champ de recherche inconnu (%s)'% champ ) + + ## Recherche avec chacun des filtres + r={} # contiendra les réponses par filtre + for i in filtres : + if (filtre_tout and filtre[i]!='(&' ) or filtre_cond[i] : + # Filtre valide + #filtre[i] += ')' + filtre[i] += '(objectClass=%s))' % i + r[i] = self.conn.search_s(self.base_dn,self.scope[i],filtre[i]) + else : + r[i] = None + + ## On a alors une liste de résultats + ## r = { categorie1 : [ (result1), (result2), ...] , ... } - # Traitement - if not r['machine'] and not r['adherent'] and not r['club'] : - # Pas de réponses - return result - elif not r['adherent'] and not r['club'] : - # Il n'y avait seulement un filtre machine - # => on retourne uniquement les machines trouvées - for m in r['machine'] : - result['machine'].append(machine(m,mode,self.conn) ) - elif not r['machine'] : - # Il n'y avait pas de filtre machine - # => on retourne uniquement les adhérents - if r['adherent'] : - for a in r['adherent'] : - result['adherent'].append(adherent(a,mode,self.conn) ) - if r['club'] : - for a in r['club'] : - result['club'].append(club(a,mode,self.conn) ) - else : - # Il faut croiser les résultats machine et propriétaire - # Traitement des machines - mach_adh = [] # liste de dn d'adhérents et de clubs - for res in r['machine'] : - dn = string.join(res[0].split(',')[-4:],',') - if dn[:3] != 'aid' and dn[:3] != 'cid' : continue - if dn not in mach_adh : - mach_adh.append(dn) - - # Croisement - bons_dn = [] # liste des dn d'adhérents qui correspondent aux critères - if r['adherent'] : - for a in r['adherent'] : - if a[0] in mach_adh and not a[0] in bons_dn : - bons_dn.append(a[0]) - result['adherent'].append(adherent(a,mode,self.conn) ) - if r['club'] : - for a in r['club'] : - if a[0] in mach_adh and not a[0] in bons_dn : - bons_dn.append(a[0]) - result['club'].append(club(a,mode,self.conn) ) - - # Maintenant c'est au tour des bonnes machines - bons_dn2 = [] - for a in r['machine'] : - dn = string.join(a[0].split(',')[-4:],',') - if dn in bons_dn and not a[0] in bons_dn2 : - bons_dn2.append(dn) - result['machine'].append(machine(a,mode,self.conn) ) - - else : - ### Recherche d'une chaine sur tous les champs - conv = { 'machine' : machine , 'club' : club, 'adherent' : adherent } - - for i in filtres : - cl = conv[i] - - # Construction du filtre - filtre = '(&(|' - for champ in self.auto_search_champs[i] : - filtre += build_filtre(champ,expression) - filtre+=')(objectClass=%s))' %i - - # Recherche - for r in self.conn.search_s(self.base_dn,self.scope[i],filtre) : - result[i].append( cl(r,mode,self.conn) ) - - return result + # Traitement + if not r['machine'] and not r['adherent'] and not r['club'] : + # Pas de réponses + return result + elif not r['adherent'] and not r['club'] : + # Il n'y avait seulement un filtre machine + # => on retourne uniquement les machines trouvées + for m in r['machine'] : + result['machine'].append(machine(m,mode,self.conn) ) + elif not r['machine'] : + # Il n'y avait pas de filtre machine + # => on retourne uniquement les adhérents + if r['adherent'] : + for a in r['adherent'] : + result['adherent'].append(adherent(a,mode,self.conn) ) + if r['club'] : + for a in r['club'] : + result['club'].append(club(a,mode,self.conn) ) + else : + # Il faut croiser les résultats machine et propriétaire + # Traitement des machines + mach_adh = [] # liste de dn d'adhérents et de clubs + for res in r['machine'] : + dn = string.join(res[0].split(',')[-4:],',') + if dn[:3] != 'aid' and dn[:3] != 'cid' : continue + if dn not in mach_adh : + mach_adh.append(dn) + + # Croisement + bons_dn = [] # liste des dn d'adhérents qui correspondent aux critères + if r['adherent'] : + for a in r['adherent'] : + if a[0] in mach_adh and not a[0] in bons_dn : + bons_dn.append(a[0]) + result['adherent'].append(adherent(a,mode,self.conn) ) + if r['club'] : + for a in r['club'] : + if a[0] in mach_adh and not a[0] in bons_dn : + bons_dn.append(a[0]) + result['club'].append(club(a,mode,self.conn) ) + + # Maintenant c'est au tour des bonnes machines + bons_dn2 = [] + for a in r['machine'] : + dn = string.join(a[0].split(',')[-4:],',') + if dn in bons_dn and not a[0] in bons_dn2 : + bons_dn2.append(dn) + result['machine'].append(machine(a,mode,self.conn) ) + + else : + ### Recherche d'une chaine sur tous les champs + conv = { 'machine' : machine , 'club' : club, 'adherent' : adherent } + + for i in filtres : + cl = conv[i] + + # Construction du filtre + filtre = '(&(|' + for champ in self.auto_search_champs[i] : + filtre += build_filtre(champ,expression) + filtre+=')(objectClass=%s))' %i + + # Recherche + for r in self.conn.search_s(self.base_dn,self.scope[i],filtre) : + result[i].append( cl(r,mode,self.conn) ) + + return result ############################################################################# @@ -616,52 +616,52 @@ class base_classes_crans(crans_ldap) : """ Méthodes de base des classes machines, et base_proprietaire """ def __del__(self) : - # Destruction des locks résiduels - for lock in self._locks : - try : - self.remove_lock(lock) - except : - pass + # Destruction des locks résiduels + for lock in self._locks : + try : + self.remove_lock(lock) + except : + pass def id(self): - """ Retourne la valeur de l'attribu caractéristique de la classe (aid,mid,cid)""" - try : - s = self.dn.split(',')[0].split('=') - if s[0] == self.idn : - return s[1] - except : - return '' + """ Retourne la valeur de l'attribu caractéristique de la classe (aid,mid,cid)""" + try : + s = self.dn.split(',')[0].split('=') + if s[0] == self.idn : + return s[1] + except : + return '' def blacklist_actif(self) : - """ - Vérifie si l'instance courante est blacklistée. - Retourne les sanctions en cours (liste) - Retourne une liste vide si aucune sanction en cours - """ + """ + Vérifie si l'instance courante est blacklistée. + Retourne les sanctions en cours (liste) + Retourne une liste vide si aucune sanction en cours + """ return self.blacklist_all()[0].keys() def blacklist_all(self) : - """ - Vérifie si l'instance courante est blacklistée ou a été blacklistée. - Retourne les sanctions en cours sous forme de dictionnaire avec comme clef + """ + Vérifie si l'instance courante est blacklistée ou a été blacklistée. + Retourne les sanctions en cours sous forme de dictionnaire avec comme clef la sanction et comme valeur une liste de couple de dates correspondant aux différentes périodes de sanctions. ex: { 'upload' : (('17/11/2004 00:00','20/11/2004 00:00'), ('...', '...')) } - """ - bl_liste = self._data.get('blacklist',[]) - - if 'machine' in self._data['objectClass'] : - # Il faut aussi regarder la blackliste du propriétaire - p = self.proprietaire() - bl_liste += p.blacklist() - - actifs = {} + """ + bl_liste = self._data.get('blacklist',[]) + + if 'machine' in self._data['objectClass'] : + # Il faut aussi regarder la blackliste du propriétaire + p = self.proprietaire() + bl_liste += p.blacklist() + + actifs = {} inactifs = {} - - for sanction in bl_liste : - s = sanction.split(',')[2] - if is_actif(sanction) : + + for sanction in bl_liste : + s = sanction.split(',')[2] + if is_actif(sanction) : if not s in actifs: actifs[s] = [] actifs[s].append((sanction.split(',')[0], @@ -671,142 +671,142 @@ class base_classes_crans(crans_ldap) : inactifs[s] = [] inactifs[s].append((sanction.split(',')[0], sanction.split(',')[1])) - return (actifs, inactifs) + return (actifs, inactifs) def blacklist(self,new=None) : - """ - Blacklistage de la ou de toutes la machines du propriétaire - new est une liste de 4 termes : - [ debut_sanction , fin_sanction, sanction, commentaire ] - début et fin doivent être sous la forme donnée par date_format - pour un début ou fin immédiate mettre now - pour une fin indéterminée mettre '-' - - pour modifier une entrée donner un tuple de deux termes : - ( index dans blacklist à modifier , nouvelle liste ) - l'index est celui obtenu dans la liste retournée par blacklist() - """ - if not self._data.has_key('blacklist') : - self._data['blacklist']=[] - liste = list(self._data['blacklist']) - if new==None : return map(decode,liste) - - if type(new)==tuple : - # Modif - index = new[0] - new = new[1] - if new=='' : - liste.pop(index) - self._set('blacklist',liste) - return liste - else : - index = -1 - - if type(new)!=list or len(new)!=4 : - raise TypeError - - # Verif que les dates sont OK - if new[0] == 'now' : - new[0] = time.strftime(date_format) - else : - try : time.strptime(new[0],date_format) - except : raise ValueError(u'Date de début blacklist invalide') + """ + Blacklistage de la ou de toutes la machines du propriétaire + new est une liste de 4 termes : + [ debut_sanction , fin_sanction, sanction, commentaire ] + début et fin doivent être sous la forme donnée par date_format + pour un début ou fin immédiate mettre now + pour une fin indéterminée mettre '-' + + pour modifier une entrée donner un tuple de deux termes : + ( index dans blacklist à modifier , nouvelle liste ) + l'index est celui obtenu dans la liste retournée par blacklist() + """ + if not self._data.has_key('blacklist') : + self._data['blacklist']=[] + liste = list(self._data['blacklist']) + if new==None : return map(decode,liste) + + if type(new)==tuple : + # Modif + index = new[0] + new = new[1] + if new=='' : + liste.pop(index) + self._set('blacklist',liste) + return liste + else : + index = -1 + + if type(new)!=list or len(new)!=4 : + raise TypeError + + # Verif que les dates sont OK + if new[0] == 'now' : + new[0] = time.strftime(date_format) + else : + try : time.strptime(new[0],date_format) + except : raise ValueError(u'Date de début blacklist invalide') - if new[1] == 'now' : - new[1] = time.strftime(date_format) - elif new[1]!='-' : - try : time.strptime(new[1],date_format) - except : raise ValueError(u'Date de fin blacklist invalide') - - new_c = ','.join(new) + if new[1] == 'now' : + new[1] = time.strftime(date_format) + elif new[1]!='-' : + try : time.strptime(new[1],date_format) + except : raise ValueError(u'Date de fin blacklist invalide') + + new_c = ','.join(new) new_c = preattr(new_c)[1] - - if index!=-1 : - liste[index] = new_c - else : - liste = liste + [ new_c ] - - if self._data['blacklist'] != liste : - self._data['blacklist']=liste - self.modifs.append('blacklist_' + new[2]) - - return liste + + if index!=-1 : + liste[index] = new_c + else : + liste = liste + [ new_c ] + + if self._data['blacklist'] != liste : + self._data['blacklist']=liste + self.modifs.append('blacklist_' + new[2]) + + return liste def restore(self) : - """ Restore les données à l'état initial """ - self._data = self._init_data.copy() - self.modifs=[] - + """ Restore les données à l'état initial """ + self._data = self._init_data.copy() + self.modifs=[] + def historique(self) : - """ Retourne l'historique de l'objet """ - return map(decode,self._data.get('historique',[])) + """ Retourne l'historique de l'objet """ + return map(decode,self._data.get('historique',[])) def info(self,new=None) : - """ - Pour ajouter une remarque new doit être la chaîne - représentant la remarque à ajouter - Pour modifier new doit être une liste de la forme : - [ index de la remarque à modifier , nouvelle remarque ] - l'index est celui obtenu dans la liste retournée par info() - """ - if not self._data.has_key('info') : - self._data['info']=[] - liste = list(self._data['info']) - if new==None : return map(decode,liste) - - if type(new)==list : - # Modif - index = new[0] - l, new = preattr(new[1]) - if not new : - # Supression remarque - liste.pop(index) - else : - # Modif remarque - liste[index]=new - elif type(new)==str : - # Remarque supplémentaire - l, new = preattr(new) - if not new : - # On ajoute pas de remarque vide - return liste - # Ajout à la liste - liste = liste + [ new ] - else : - raise TypeError + """ + Pour ajouter une remarque new doit être la chaîne + représentant la remarque à ajouter + Pour modifier new doit être une liste de la forme : + [ index de la remarque à modifier , nouvelle remarque ] + l'index est celui obtenu dans la liste retournée par info() + """ + if not self._data.has_key('info') : + self._data['info']=[] + liste = list(self._data['info']) + if new==None : return map(decode,liste) + + if type(new)==list : + # Modif + index = new[0] + l, new = preattr(new[1]) + if not new : + # Supression remarque + liste.pop(index) + else : + # Modif remarque + liste[index]=new + elif type(new)==str : + # Remarque supplémentaire + l, new = preattr(new) + if not new : + # On ajoute pas de remarque vide + return liste + # Ajout à la liste + liste = liste + [ new ] + else : + raise TypeError - self._set('info',liste) - return liste + self._set('info',liste) + return liste def _save(self) : - """ Sauvegarde dans la base LDAP """ - if not self.modifs : - # Rien à faire - return [] - - if not self.dn : - # Enregistrement à placer en tête de base - self.dn = self.base_dn - - # Construction de l'historique - if not self._init_data : - modif='inscription' - else : - ### ON NE TOUCHE PAS A SELF.MODIFS, IL EST UTILISÉ PLUS LOIN !!!!!!! - modif=', '.join(self.modifs) + """ Sauvegarde dans la base LDAP """ + if not self.modifs : + # Rien à faire + return [] + + if not self.dn : + # Enregistrement à placer en tête de base + self.dn = self.base_dn + + # Construction de l'historique + if not self._init_data : + modif='inscription' + else : + ### ON NE TOUCHE PAS A SELF.MODIFS, IL EST UTILISÉ PLUS LOIN !!!!!!! + modif=', '.join(self.modifs) if "chbre" in self.modifs: - modif = modif.replace('chbre', "chbre %s -> %s" % (self._init_data["chbre"][0], + modif = modif.replace('chbre', "chbre %s -> %s" % (self._init_data["chbre"][0], self._data["chbre"][0])) - if "solde" in self.modifs: - diff = float(self._init_data.get('solde',[0])[0]) - float(self._data.get('solde',[0])[0]) - if diff > 0 : - modif = modif.replace("solde", "debit %s Euros" % str(diff) ) - else : - modif = modif.replace("solde", "credit %s Euros" % str(-diff) ) + if "solde" in self.modifs: + diff = float(self._init_data.get('solde',[0])[0]) - float(self._data.get('solde',[0])[0]) + if diff > 0 : + modif = modif.replace("solde", "debit %s Euros" % str(diff) ) + else : + modif = modif.replace("solde", "credit %s Euros" % str(-diff) ) - timestamp = localtime() - hist = "%s, %s" % ( time.strftime(date_format, timestamp), script_utilisateur ) + timestamp = localtime() + hist = "%s, %s" % ( time.strftime(date_format, timestamp), script_utilisateur ) # On loggue try: @@ -816,410 +816,410 @@ class base_classes_crans(crans_ldap) : fd.close() except: pass - - # Suffit-t-il d'ajouter un item au dernier élément de l'historique ? + + # Suffit-t-il d'ajouter un item au dernier élément de l'historique ? try: - dern = self._data['historique'][-1].split(' : ',2) - if dern[0] == hist : - # Même date et même cableur - if modif not in dern[1].split(', ') : - # Qqch de plus de modifié - self._data['historique'][-1] = self._data['historique'][-1] + ', ' +modif - else : - # Nouvelle entrée - # NE PAS UTILISER L'OPERATEUR += ICI sinon self._init_data aussi modififié - self._data['historique'] = self._data['historique'] + [ "%s : %s" % ( hist, modif ) ] - except: - # Nouvelle inscription - self._data['historique'] = [ "%s : %s" % ( hist, modif ) ] - - if not self._init_data : - ### Nouvel enregistrement - # Génération du dn - res = self.conn.search_s(self.base_dn,2,'objectClass=%s' % self._data['objectClass'][0],['']) - vidn=1 - vidns=[] - # Liste des dn pris - for r in res : - # r=( dn, {} ) - r = r[0].split(',')[0] - if r[:4] != '%s=' % self.idn : continue - vidns.append(int(r[4:])) - # On prend le premier libre - while vidn in vidns : - vidn += 1 + dern = self._data['historique'][-1].split(' : ',2) + if dern[0] == hist : + # Même date et même cableur + if modif not in dern[1].split(', ') : + # Qqch de plus de modifié + self._data['historique'][-1] = self._data['historique'][-1] + ', ' +modif + else : + # Nouvelle entrée + # NE PAS UTILISER L'OPERATEUR += ICI sinon self._init_data aussi modififié + self._data['historique'] = self._data['historique'] + [ "%s : %s" % ( hist, modif ) ] + except: + # Nouvelle inscription + self._data['historique'] = [ "%s : %s" % ( hist, modif ) ] + + if not self._init_data : + ### Nouvel enregistrement + # Génération du dn + res = self.conn.search_s(self.base_dn,2,'objectClass=%s' % self._data['objectClass'][0],['']) + vidn=1 + vidns=[] + # Liste des dn pris + for r in res : + # r=( dn, {} ) + r = r[0].split(',')[0] + if r[:4] != '%s=' % self.idn : continue + vidns.append(int(r[4:])) + # On prend le premier libre + while vidn in vidns : + vidn += 1 - self.dn='%s=%s,%s' % (self.idn, vidn, self.dn) - self._data[self.idn]= [ '%d' % vidn ] - - # Ecriture - modlist = ldap.modlist.addModlist(self._data) - self.conn.add_s(self.dn,modlist) - else : - ### Modification entrée - if not self._modifiable : - raise RuntimeError(u'Objet non modifiable') - modlist = ldap.modlist.modifyModlist(self._init_data,self._data) - try : - self.conn.modify_s(self.dn,modlist) - except ldap.TYPE_OR_VALUE_EXISTS , c : - champ = c.args[0]['info'].split(':')[0] - raise RuntimeError(u'Entrée en double dans le champ %s' % champ) - - ### Génération de la liste de services à redémarrer - # Quasiement tout est traité dans les classes filles. - for m in self.modifs : - if sre.match('blacklist_*',m) : - self.services_to_restart(m) - - # Reinitialisation - self._init_data = self._data.copy() - + self.dn='%s=%s,%s' % (self.idn, vidn, self.dn) + self._data[self.idn]= [ '%d' % vidn ] + + # Ecriture + modlist = ldap.modlist.addModlist(self._data) + self.conn.add_s(self.dn,modlist) + else : + ### Modification entrée + if not self._modifiable : + raise RuntimeError(u'Objet non modifiable') + modlist = ldap.modlist.modifyModlist(self._init_data,self._data) + try : + self.conn.modify_s(self.dn,modlist) + except ldap.TYPE_OR_VALUE_EXISTS , c : + champ = c.args[0]['info'].split(':')[0] + raise RuntimeError(u'Entrée en double dans le champ %s' % champ) + + ### Génération de la liste de services à redémarrer + # Quasiement tout est traité dans les classes filles. + for m in self.modifs : + if sre.match('blacklist_*',m) : + self.services_to_restart(m) + + # Reinitialisation + self._init_data = self._data.copy() + def _delete(self,dn,comment='') : - """ Sauvegarde puis destruction du dn (et des sous-dn) fourni """ - # Commentaires - comment = preattr(comment)[1] - self.modifs.append('destruction (%s)' % comment) - self._save() - - # Sauvegarde - t = str(self.__class__).split('.')[-1] - fd = open('%s/%s/%s_%s' % (config.cimetiere, t, time.strftime('%Y-%m-%d-%H:%M'), self.nom()),'wb') - self.conn = None # Fermeture des connexions à la base sinon cPickle ne marchera pas - self.rw_conn = None - cPickle.dump(self,fd,2) - fd.close() - index = u"%s, %s : %s %s # %s\n" % (time.strftime(date_format), script_utilisateur, t, self.Nom() , decode(comment)) - - self.connect() # Reconnexion à la base - # Destruction - data = self.conn.search_s(dn,2) - - data.reverse() # Necessaire pour détruire d'abord les sous-dn - for r in data : - self.conn.delete_s(r[0]) - - try : - log = open(config.cimetiere + '/index','a') - log.write(index) - log.close() - except : - pass - + """ Sauvegarde puis destruction du dn (et des sous-dn) fourni """ + # Commentaires + comment = preattr(comment)[1] + self.modifs.append('destruction (%s)' % comment) + self._save() + + # Sauvegarde + t = str(self.__class__).split('.')[-1] + fd = open('%s/%s/%s_%s' % (config.cimetiere, t, time.strftime('%Y-%m-%d-%H:%M'), self.nom()),'wb') + self.conn = None # Fermeture des connexions à la base sinon cPickle ne marchera pas + self.rw_conn = None + cPickle.dump(self,fd,2) + fd.close() + index = u"%s, %s : %s %s # %s\n" % (time.strftime(date_format), script_utilisateur, t, self.Nom() , decode(comment)) + + self.connect() # Reconnexion à la base + # Destruction + data = self.conn.search_s(dn,2) + + data.reverse() # Necessaire pour détruire d'abord les sous-dn + for r in data : + self.conn.delete_s(r[0]) + + try : + log = open(config.cimetiere + '/index','a') + log.write(index) + log.close() + except : + pass + def _set(self,champ,val) : - """ Met à jour les données de data et modifie modifs si besoin """ - if not self._data.has_key(champ) \ - or self._data.has_key(champ) and self._data[champ]!=val : - self._data[champ]=val - if champ not in self.modifs : - self.modifs.append(champ) - + """ Met à jour les données de data et modifie modifs si besoin """ + if not self._data.has_key(champ) \ + or self._data.has_key(champ) and self._data[champ]!=val : + self._data[champ]=val + if champ not in self.modifs : + self.modifs.append(champ) + ############################################################################# class base_proprietaire(base_classes_crans) : """ Méthodes de bases pour les classes adherent et club """ def __init__(self,data=(),mode='',conn=None) : - """ - Si data est fourni initialise l'adhérent avec les valeurs données - Format de data : tuple comme retourné par une recherche dans la base ldap: - ( dn, { donnée }) - Si mode='w' : le propriétaire pourra être modifié - Attention, si mode ='w' mais si l'objet est déja locké il n'y a pas d'erreur - vérifier l'obtetion du lock grace à la valeur de _modifiable (si =w c'est bon) - Il est inutile de préciser le mode pour un nouveau proprietaire - - conn est une instance de la classe de connexion à la base LDAP - """ - self.conn = conn - if not self.conn : self.connect() - - if type(data) != tuple : - raise TypeError - - self.modifs=[] - self._locks = [] + """ + Si data est fourni initialise l'adhérent avec les valeurs données + Format de data : tuple comme retourné par une recherche dans la base ldap: + ( dn, { donnée }) + Si mode='w' : le propriétaire pourra être modifié + Attention, si mode ='w' mais si l'objet est déja locké il n'y a pas d'erreur + vérifier l'obtetion du lock grace à la valeur de _modifiable (si =w c'est bon) + Il est inutile de préciser le mode pour un nouveau proprietaire + + conn est une instance de la classe de connexion à la base LDAP + """ + self.conn = conn + if not self.conn : self.connect() + + if type(data) != tuple : + raise TypeError + + self.modifs=[] + self._locks = [] - if data : - self.dn=data[0] - if mode == 'w' : - try : - self._locks.append(self.lock(self.idn, self.id())) - self._modifiable = 'w' - except EnvironmentError , c: - self._modifiable = 0 - else : - self._modifiable = 0 - # Utile pour construire l'instruction LDAP de modif - self._init_data = data[1].copy() - self._data = data[1] - else : - # Propriétaire vide - self.dn='' # Génération du reste au moment de l'écriture - self._data={ 'objectClass' : [ self.objectClass ] } - self._init_data={} - self._modifiable = 'w' - + if data : + self.dn=data[0] + if mode == 'w' : + try : + self._locks.append(self.lock(self.idn, self.id())) + self._modifiable = 'w' + except EnvironmentError , c: + self._modifiable = 0 + else : + self._modifiable = 0 + # Utile pour construire l'instruction LDAP de modif + self._init_data = data[1].copy() + self._data = data[1] + else : + # Propriétaire vide + self.dn='' # Génération du reste au moment de l'écriture + self._data={ 'objectClass' : [ self.objectClass ] } + self._init_data={} + self._modifiable = 'w' + def chsh(self,new=None) : - """ Retourne ou change le shell de l'adhérent """ - if new == None : - try : return decode(self._data.get('loginShell',[''])[0]) - except : return '' - else : - new = preattr(new)[1] - self._set('loginShell',[new]) - return new - + """ Retourne ou change le shell de l'adhérent """ + if new == None : + try : return decode(self._data.get('loginShell',[''])[0]) + except : return '' + else : + new = preattr(new)[1] + self._set('loginShell',[new]) + return new + def alias(self,new=None) : - """ - Création ou visualisation des alias mail - Même sytème d'argument que la méthode info. - """ - if not self._data.has_key('mailAlias') : - self._data['mailAlias']=[] - liste = list(self._data['mailAlias']) - if new==None : - return map(decode,liste) - - if type(new)==list : - # Modif - index = new[0] - new = new[1] - if new=='' : - # Supression alias - liste.pop(index) - self._set('mailAlias',liste) - return liste - else : - new = new.replace('@crans.org','') - index=-1 - - # Tests - l, new = preattr(new) - new = new.lower() - if l<2 : - raise ValueError(u"Alias trop court.") - for c in new[:]: - if not c in (string.letters + string.digits + '-_.') : - raise ValueError(u"Alias : seuls les caractères alphanumériques, le -, le _ et le . sont autorisés." ) - if new[0] not in string.letters : - raise ValueError(u"Le premier caractère de l'alias doit être alphabétique.") - if mailexist(new) : - raise ValueError(u"Alias existant ou correspondand à un compte.") - - if index!=-1 : - liste[index]=new - else : - liste = liste + [ new ] - - # Lock de mailAlias - self._locks.append(self.lock('mailAlias',new)) - - self._set('mailAlias',liste) - return liste + """ + Création ou visualisation des alias mail + Même sytème d'argument que la méthode info. + """ + if not self._data.has_key('mailAlias') : + self._data['mailAlias']=[] + liste = list(self._data['mailAlias']) + if new==None : + return map(decode,liste) + + if type(new)==list : + # Modif + index = new[0] + new = new[1] + if new=='' : + # Supression alias + liste.pop(index) + self._set('mailAlias',liste) + return liste + else : + new = new.replace('@crans.org','') + index=-1 + + # Tests + l, new = preattr(new) + new = new.lower() + if l<2 : + raise ValueError(u"Alias trop court.") + for c in new[:]: + if not c in (string.letters + string.digits + '-_.') : + raise ValueError(u"Alias : seuls les caractères alphanumériques, le -, le _ et le . sont autorisés." ) + if new[0] not in string.letters : + raise ValueError(u"Le premier caractère de l'alias doit être alphabétique.") + if mailexist(new) : + raise ValueError(u"Alias existant ou correspondand à un compte.") + + if index!=-1 : + liste[index]=new + else : + liste = liste + [ new ] + + # Lock de mailAlias + self._locks.append(self.lock('mailAlias',new)) + + self._set('mailAlias',liste) + return liste def machines(self) : - """ Retourne les machines (instances) appartenant à la classe """ - if self.id() : - res = [] - try : - for r in self.conn.search_s('%s=%s,%s' % ( self.idn,self.id() , self.base_dn ),1,'objectClass=machine') : - res.append(machine(r, self._modifiable,self.conn) ) - return res - except : - return [] - else : - return [] + """ Retourne les machines (instances) appartenant à la classe """ + if self.id() : + res = [] + try : + for r in self.conn.search_s('%s=%s,%s' % ( self.idn,self.id() , self.base_dn ),1,'objectClass=machine') : + res.append(machine(r, self._modifiable,self.conn) ) + return res + except : + return [] + else : + return [] def solde(self, operation=None) : """ Retourne ou modifie le solde d'un propriétaire - operation doit être un nombre positif ou négatif - (string ou int ou float) - """ - solde = float(self._data.get('solde',[0])[0]) - - if operation==None : - return solde - - # On effectue une opération - try : - new = solde + float(operation.replace(',','.')) - except ValueError : - raise ValueError(u"Il faut donner un nombre en argument.") - - # découvert accepté - if new < config.decouvert : - raise ValueError(u"Solde minimal atteind, opération non effectuée.") - - self._set('solde',[str(new)]) - return new + operation doit être un nombre positif ou négatif + (string ou int ou float) + """ + solde = float(self._data.get('solde',[0])[0]) + + if operation==None : + return solde + + # On effectue une opération + try : + new = solde + float(operation.replace(',','.')) + except ValueError : + raise ValueError(u"Il faut donner un nombre en argument.") + + # découvert accepté + if new < config.decouvert : + raise ValueError(u"Solde minimal atteind, opération non effectuée.") + + self._set('solde',[str(new)]) + return new def paiement(self,action=None) : - """ - Action est un entier représentant une année - si positif ajoute l'année à la liste - si négatif le supprime - """ - return self._an('paiement',action) + """ + Action est un entier représentant une année + si positif ajoute l'année à la liste + si négatif le supprime + """ + return self._an('paiement',action) def delete(self,comment='') : - """Destruction du proprietaire""" - - for m in self.machines() : - # Destruction machines - m.delete(comment) - - self._delete(self.dn,comment) - - try : - if self.compte() : - args = self._data['uid'][0] + ',' - args+= self._data['homeDirectory'][0] - self.services_to_restart('del_user',[ args ] ) - except : - # Si ne peux avoir de compte - pass - + """Destruction du proprietaire""" + + for m in self.machines() : + # Destruction machines + m.delete(comment) + + self._delete(self.dn,comment) + + try : + if self.compte() : + args = self._data['uid'][0] + ',' + args+= self._data['homeDirectory'][0] + self.services_to_restart('del_user',[ args ] ) + except : + # Si ne peux avoir de compte + pass + def save(self) : - """ - Enregistre l'adhérent ou le club courant dans la base LDAP - Ajoute le mail de bienvenue à la liste des services à redémarrer - Retourne une chaîne indiquant les opération effectuées. - """ - # Note : un peu trop de fonctions pour un club mais ce n'est pas génant - - ret ='' - if self._init_data : - nouveau =0 - # Reconfiguration switch si changement de chambre et si machine fixe - if 'chbre' in self.modifs : - for m in self.machines() : - if not m.ipsec() : - self.services_to_restart('switch',[self._data['chbre'][0]]) - self.services_to_restart('switch',[self._init_data.get('chbre','')[0]]) - break - else : - nouveau = 1 + """ + Enregistre l'adhérent ou le club courant dans la base LDAP + Ajoute le mail de bienvenue à la liste des services à redémarrer + Retourne une chaîne indiquant les opération effectuées. + """ + # Note : un peu trop de fonctions pour un club mais ce n'est pas génant + + ret ='' + if self._init_data : + nouveau =0 + # Reconfiguration switch si changement de chambre et si machine fixe + if 'chbre' in self.modifs : + for m in self.machines() : + if not m.ipsec() : + self.services_to_restart('switch',[self._data['chbre'][0]]) + self.services_to_restart('switch',[self._init_data.get('chbre','')[0]]) + break + else : + nouveau = 1 - if 'chbre' in self.modifs and '????' in [ self._init_data.get("chbre",[''])[0] , self._init_data.get("chbre",[''])[0] ] : - self.services_to_restart('bl_chbre_invalide') - - # Enregistrement - self._save() - - # Message de sortie - if nouveau : - ret += coul(u"%s inscrit avec succès." % self.Nom(), 'vert') - - if self.idn !='cid' : - # Mail de bienvenue - self.services_to_restart('mail_bienvenue',[self.mail().encode('iso-8859-15')]) - - else : - ret += coul(u"Modification %s effectuée avec succès." % self.Nom(), 'vert') - - # Faut-il redémarrer plus de services que ceux traités dans _save ? - if 'carteEtudiant+%s' % ann_scol in self.modifs \ - or 'carteEtudiant-%s' % ann_scol in self.modifs \ - and self.machines() : - self.services_to_restart('bl_carte_etudiant') - - if 'paiement+%s' % ann_scol in self.modifs \ - or 'paiement-%s' % ann_scol in self.modifs : - for m in self.machines() : - self.services_to_restart('firewall',[m.ip()] ) - self.services_to_restart('firewall-komaz',[m.ip()] ) - self.services_to_restart('dns') - if m.ipsec() : - self.services_to_restart('conf_wifi') - self.services_to_restart('dhcp-nectaris') - else : - self.services_to_restart('switch',[self.chbre()]) + if 'chbre' in self.modifs and '????' in [ self._init_data.get("chbre",[''])[0] , self._init_data.get("chbre",[''])[0] ] : + self.services_to_restart('bl_chbre_invalide') + + # Enregistrement + self._save() + + # Message de sortie + if nouveau : + ret += coul(u"%s inscrit avec succès." % self.Nom(), 'vert') + + if self.idn !='cid' : + # Mail de bienvenue + self.services_to_restart('mail_bienvenue',[self.mail().encode('iso-8859-15')]) + + else : + ret += coul(u"Modification %s effectuée avec succès." % self.Nom(), 'vert') + + # Faut-il redémarrer plus de services que ceux traités dans _save ? + if 'carteEtudiant+%s' % ann_scol in self.modifs \ + or 'carteEtudiant-%s' % ann_scol in self.modifs \ + and self.machines() : + self.services_to_restart('bl_carte_etudiant') + + if 'paiement+%s' % ann_scol in self.modifs \ + or 'paiement-%s' % ann_scol in self.modifs : + for m in self.machines() : + self.services_to_restart('firewall',[m.ip()] ) + self.services_to_restart('firewall-komaz',[m.ip()] ) + self.services_to_restart('dns') + if m.ipsec() : + self.services_to_restart('conf_wifi') + self.services_to_restart('dhcp-nectaris') + else : + self.services_to_restart('switch',[self.chbre()]) self.services_to_restart('dhcp') - # Vérification si changement de bât, ce qui obligerai un changement d'IP - if 'chbre' in self.modifs and self.chbre()!='????' : - # Verif si machines avec bonnes ip - err = 0 - for m in self.machines() : - if m.ipsec() : - # Machine Wifi - continue - # Machine fixe - ip = m.ip() - try : - # Tentative de changement d'IP de la machine - m.ip(ip) - except ValueError: - # IP invalide, on la change - ret += "\nChangement d'IP machine %s : " % m.nom() - try : - ret += "%s -> %s" % ( ip, m.ip('') ) - m.save() - except Exception, c : - ret += coul(u'ERREUR : %s' % c.args[0], rouge) - err = 1 - - if err : ret += '\nEssayer de corriger les erreurs machines en éditant celles-ci.\n' + # Vérification si changement de bât, ce qui obligerai un changement d'IP + if 'chbre' in self.modifs and self.chbre()!='????' : + # Verif si machines avec bonnes ip + err = 0 + for m in self.machines() : + if m.ipsec() : + # Machine Wifi + continue + # Machine fixe + ip = m.ip() + try : + # Tentative de changement d'IP de la machine + m.ip(ip) + except ValueError: + # IP invalide, on la change + ret += "\nChangement d'IP machine %s : " % m.nom() + try : + ret += "%s -> %s" % ( ip, m.ip('') ) + m.save() + except Exception, c : + ret += coul(u'ERREUR : %s' % c.args[0], rouge) + err = 1 + + if err : ret += '\nEssayer de corriger les erreurs machines en éditant celles-ci.\n' - # Faut-il créer un compte sur zamok ? - if 'compte' in self.modifs : - ret += u'\nUn compte a été créé :\n login : %s\n' % self.compte() - args = self._data['homeDirectory'][0] + ',' - args+= self._data['uidNumber'][0] + ',' - args+= self._data['uid'][0] - self.services_to_restart('home',[ args ]) - r = prompt("Attribuer tout de suite un mot de passe ? [O/N]","O") - if r=='O' or r=='o' : - chgpass(self.dn) - else : - ret += coul(u' Il faudra penser à attribuer un mot de passe\n','jaune') - - # Modif des droits ? - if 'droits' in self.modifs : - self.services_to_restart('droits',[self._data['uid']]) + # Faut-il créer un compte sur zamok ? + if 'compte' in self.modifs : + ret += u'\nUn compte a été créé :\n login : %s\n' % self.compte() + args = self._data['homeDirectory'][0] + ',' + args+= self._data['uidNumber'][0] + ',' + args+= self._data['uid'][0] + self.services_to_restart('home',[ args ]) + r = prompt("Attribuer tout de suite un mot de passe ? [O/N]","O") + if r=='O' or r=='o' : + chgpass(self.dn) + else : + ret += coul(u' Il faudra penser à attribuer un mot de passe\n','jaune') + + # Modif des droits ? + if 'droits' in self.modifs : + self.services_to_restart('droits',[self._data['uid']]) - # Remise à zero - self.modifs=[] - - return ret + # Remise à zero + self.modifs=[] + + return ret def _an(self,champ,action) : - """ - Champ est un champ contenant une liste d'entiers - Action est un entier représentant une année - si positif ajoute l'année à la liste - si négatif le supprime - """ - if not self._data.has_key(champ) : - trans=[] - else : - # On va travailler sur une liste d'entiers - trans = map(int,self._data[champ]) + """ + Champ est un champ contenant une liste d'entiers + Action est un entier représentant une année + si positif ajoute l'année à la liste + si négatif le supprime + """ + if not self._data.has_key(champ) : + trans=[] + else : + # On va travailler sur une liste d'entiers + trans = map(int,self._data[champ]) - if action==None : - return trans + if action==None : + return trans - if type(action)!=int : raise TypeError - - if action>0 and action not in trans : - trans.append(action) - act = '%s+%d' % (champ,action) - if act not in self.modifs : - self.modifs.append(act) - elif action<0 and -action in trans : - trans.remove(-action) - act = '%s%s' % (champ,action) - if act not in self.modifs : - self.modifs.append(act) + if type(action)!=int : raise TypeError + + if action>0 and action not in trans : + trans.append(action) + act = '%s+%d' % (champ,action) + if act not in self.modifs : + self.modifs.append(act) + elif action<0 and -action in trans : + trans.remove(-action) + act = '%s%s' % (champ,action) + if act not in self.modifs : + self.modifs.append(act) - trans.sort() - new=[] - for an in trans : - new.append('%d' % an ) - - self._data[champ] = new - - return self._data[champ] + trans.sort() + new=[] + for an in trans : + new.append('%d' % an ) + + self._data[champ] = new + + return self._data[champ] ############################################################################# @@ -1231,171 +1231,171 @@ class adherent(base_proprietaire) : ### Méthodes Nom utilisée lors de l'affichage des propriétés ### (commune avec les classes crans et club) def Nom(self) : - """ Retourne prenom nom """ - return "%s %s" % ( self.prenom() , self.nom() ) - + """ Retourne prenom nom """ + return "%s %s" % ( self.prenom() , self.nom() ) + def nom(self,new=None) : - return self.__nom_prenom('nom',new) + return self.__nom_prenom('nom',new) def prenom(self,new=None) : - return self.__nom_prenom('prenom',new) + return self.__nom_prenom('prenom',new) def __nom_prenom(self,champ,new) : - if new==None : - return decode(self._data.get(champ,[''])[0]) - - l, new = preattr(new) - new = new.capitalize() - for c in new[:] : - if c not in (string.letters + '- ' + preattr(accents)[1] ) : - raise ValueError(u"Seuls les caractères alphabétiques, l'espace et le - sont permis dans %s." % champ.replace(u'e',u'é') ) - if l<2 : - raise ValueError(u"%s trop court." % champ.capitalize().replace(u'e',u'é')) - if new[0] not in string.letters : - raise ValueError(u"Le premier caractère du %s doit être une lettre" % champ.replace(u'e',u'é') ) - - self._set(champ,[new]) - return new + if new==None : + return decode(self._data.get(champ,[''])[0]) + + l, new = preattr(new) + new = new.capitalize() + for c in new[:] : + if c not in (string.letters + '- ' + preattr(accents)[1] ) : + raise ValueError(u"Seuls les caractères alphabétiques, l'espace et le - sont permis dans %s." % champ.replace(u'e',u'é') ) + if l<2 : + raise ValueError(u"%s trop court." % champ.capitalize().replace(u'e',u'é')) + if new[0] not in string.letters : + raise ValueError(u"Le premier caractère du %s doit être une lettre" % champ.replace(u'e',u'é') ) + + self._set(champ,[new]) + return new def tel(self,new=None) : - if new==None : - return self._data.get('tel',[''])[0] - - if new != 'inconnu' : - l, new = preattr(new) - if not new.isdigit() or l<6 or l>15 : - raise ValueError(u"Numéro de téléphone incorrect (il doit comporter uniquement des chiffres).") - - self._set('tel',[new]) - return new + if new==None : + return self._data.get('tel',[''])[0] + + if new != 'inconnu' : + l, new = preattr(new) + if not new.isdigit() or l<6 or l>15 : + raise ValueError(u"Numéro de téléphone incorrect (il doit comporter uniquement des chiffres).") + + self._set('tel',[new]) + return new def chbre(self,new=None) : - """ - Défini la chambre d'un adhérent, EXT pour personne extérieure au campus - """ - if new==None : - return decode(self._data.get('chbre',[''])[0]) - - l, new = preattr(new) - if l==0 : - raise ValueError(u"Chambre incorrecte.") - - if new.upper() == 'EXT' : - # N'est pas ou plus sur le campus - # Machine fixe ? - # for m in self.machines() : - # if not m.ipsec() : - # raise ValueError(u'Un adhérent en dehors du campus ne doit pas avoir de machine fixe.') - - self._set('chbre',['EXT']) - return 'EXT' - elif new.upper() == '????' : - # On ne sait pas ou est l'adhérent - self._set('chbre',['????']) - return '????' - - new = new.capitalize() - bat = new[0].lower() - - if bat in annuaires.chbre_prises.keys() : - # On a la liste des chambres - chbres = annuaires.chbre_prises[bat].keys() - if new[1:] not in chbres or len(new)<4 or not new[1:4].isdigit() : - chbres.sort() - aide = u"Chambre inconnue dans le batiment, les chambres valides sont :" - a=0 - for c in chbres : - if len(c)>=3 and not c[:3].isdigit() : - # C'est un local club - continue - if int(a/14)>int((a-1)/14) : aide += '\n ' - if c[0]!='X' : - aide += c.ljust(5) - a=a+1 - aide += u'\n' - aide += u" " + annuaires.aide.get(bat,'') - raise ValueError(aide) - - else : - raise ValueError(u'Bâtiment inconnu.') - - # La chambre est valide, est-elle déja occupée ? - test = self.exist('chbre=%s' % new) - if test : - search = test[0].split(',')[0] - if search.split('=')[0]!='aid' : - raise ValueError(u'Chambre déjà occupée.') - adh = self.search(search,self._modifiable)['adherent'] - if len(adh) != 1 : - raise ValueError(u'Chambre déjà occupée.') - else : - raise ValueError(u'Chambre déjà occupée.',adh[0]) - - # Lock de la chambre - self._locks.append(self.lock('chbre',new)) - - self._set('chbre',[new]) - return new + """ + Défini la chambre d'un adhérent, EXT pour personne extérieure au campus + """ + if new==None : + return decode(self._data.get('chbre',[''])[0]) + + l, new = preattr(new) + if l==0 : + raise ValueError(u"Chambre incorrecte.") + + if new.upper() == 'EXT' : + # N'est pas ou plus sur le campus + # Machine fixe ? + # for m in self.machines() : + # if not m.ipsec() : + # raise ValueError(u'Un adhérent en dehors du campus ne doit pas avoir de machine fixe.') + + self._set('chbre',['EXT']) + return 'EXT' + elif new.upper() == '????' : + # On ne sait pas ou est l'adhérent + self._set('chbre',['????']) + return '????' + + new = new.capitalize() + bat = new[0].lower() + + if bat in annuaires.chbre_prises.keys() : + # On a la liste des chambres + chbres = annuaires.chbre_prises[bat].keys() + if new[1:] not in chbres or len(new)<4 or not new[1:4].isdigit() : + chbres.sort() + aide = u"Chambre inconnue dans le batiment, les chambres valides sont :" + a=0 + for c in chbres : + if len(c)>=3 and not c[:3].isdigit() : + # C'est un local club + continue + if int(a/14)>int((a-1)/14) : aide += '\n ' + if c[0]!='X' : + aide += c.ljust(5) + a=a+1 + aide += u'\n' + aide += u" " + annuaires.aide.get(bat,'') + raise ValueError(aide) + + else : + raise ValueError(u'Bâtiment inconnu.') + + # La chambre est valide, est-elle déja occupée ? + test = self.exist('chbre=%s' % new) + if test : + search = test[0].split(',')[0] + if search.split('=')[0]!='aid' : + raise ValueError(u'Chambre déjà occupée.') + adh = self.search(search,self._modifiable)['adherent'] + if len(adh) != 1 : + raise ValueError(u'Chambre déjà occupée.') + else : + raise ValueError(u'Chambre déjà occupée.',adh[0]) + + # Lock de la chambre + self._locks.append(self.lock('chbre',new)) + + self._set('chbre',[new]) + return new def adresse(self,new=None): - """ Défini l'adresse pour les personnes extérieures (dont la chambre = EXT) - L'adresse est une liste de 4 éléments : numero, rue, code postal, ville - """ - if new==None : - if self.chbre() != 'EXT' : - # Personne sur le campus - return '' - else : - return map(decode,self._data.get('postalAddress', ['','','',''])[:4]) - - if type(new)!=list and len(new)!=4 : - raise TypeError - - l_min = [ 2, 0, 5, 2 ] - for i in range(0,4) : - l, new[i] = preattr(new[i]) - if l < l_min[i] : raise ValueError(u"Adresse incorrecte.") - - # Correction si necessaire - if not new[1] : - new[1] = ' ' - - self._set('postalAddress',new) - return new + """ Défini l'adresse pour les personnes extérieures (dont la chambre = EXT) + L'adresse est une liste de 4 éléments : numero, rue, code postal, ville + """ + if new==None : + if self.chbre() != 'EXT' : + # Personne sur le campus + return '' + else : + return map(decode,self._data.get('postalAddress', ['','','',''])[:4]) + + if type(new)!=list and len(new)!=4 : + raise TypeError + + l_min = [ 2, 0, 5, 2 ] + for i in range(0,4) : + l, new[i] = preattr(new[i]) + if l < l_min[i] : raise ValueError(u"Adresse incorrecte.") + + # Correction si necessaire + if not new[1] : + new[1] = ' ' + + self._set('postalAddress',new) + return new def mail(self,new=None) : - if new==None : - return decode(self._data.get('mail',[''])[0]) - - l, new = preattr(new) - new = new.lower() - - #Emplacement de l'@ - a=new.find('@') - #Emplacement du . final - b=new.rfind('.') - - # Les tests : - # exactement un @ - # 2 ou 3 caractères après le . final - # @ pas en premier ni juste avant le dernier . - if new.count('@')!=1 \ - or not ( l-b==4 or l-b==3) \ - or a<1 or b-a<2 : - raise ValueError(u"Adresse mail incorrecte.") - - # Pas de caractèrs bizarres - for l in new[:]: - if not l in (string.lowercase + string.digits + '-_.@') : - raise ValueError(u"Caractère interdits dans l'adresse mail (%s)." % l) - - # Pour les vicieux - if sre.match('.*crans.(org|ens-cachan.fr)$',new) : - raise ValueError(u"Adresse mail @crans interdite ici") - - self._set('mail',[new]) + if new==None : + return decode(self._data.get('mail',[''])[0]) - # Il ne doit pas y avoir de compte + l, new = preattr(new) + new = new.lower() + + #Emplacement de l'@ + a=new.find('@') + #Emplacement du . final + b=new.rfind('.') + + # Les tests : + # exactement un @ + # 2 ou 3 caractères après le . final + # @ pas en premier ni juste avant le dernier . + if new.count('@')!=1 \ + or not ( l-b==4 or l-b==3) \ + or a<1 or b-a<2 : + raise ValueError(u"Adresse mail incorrecte.") + + # Pas de caractèrs bizarres + for l in new[:]: + if not l in (string.lowercase + string.digits + '-_.@') : + raise ValueError(u"Caractère interdits dans l'adresse mail (%s)." % l) + + # Pour les vicieux + if sre.match('.*crans.(org|ens-cachan.fr)$',new) : + raise ValueError(u"Adresse mail @crans interdite ici") + + self._set('mail',[new]) + + # Il ne doit pas y avoir de compte self._data['objectClass'] = [ 'adherent' ] for c in [ 'uid', 'cn', 'shadowLastChange', 'shadowMax', 'shadowWarning', 'loginShell', 'userPassword', 'uidNumber', 'gidNumber', 'homeDirectory', 'gecos', 'droits','mailAlias', 'cannonicalAlias' ] : @@ -1405,171 +1405,171 @@ class adherent(base_proprietaire) : return new def etudes(self,index_or_new) : - """ - Retourne l'un des 3 champs études (selon index_or_new si entier) - """ - if type(index_or_new)==int : - if self._data.has_key('etudes'): - return decode(self._data['etudes'][index_or_new]) - else: - return '' + """ + Retourne l'un des 3 champs études (selon index_or_new si entier) + """ + if type(index_or_new)==int : + if self._data.has_key('etudes'): + return decode(self._data['etudes'][index_or_new]) + else: + return '' - if type(index_or_new)!=list : - raise TypeError + if type(index_or_new)!=list : + raise TypeError - if not self._data.has_key('etudes') : - self._data['etudes']=['','',''] + if not self._data.has_key('etudes') : + self._data['etudes']=['','',''] - # Pas grand chose à faire à part vérifier que ce sont bien des chaines - if len(index_or_new)!=3 : - raise ValueError(u"Format études non valides.") - - new = ['','',''] - for i in range(0,3) : - n = preattr(index_or_new[i])[1] - if n in new or n=='' : - raise ValueError(u"Etudes non valides.") - new[i] = n - - self._set('etudes',new) - - return new + # Pas grand chose à faire à part vérifier que ce sont bien des chaines + if len(index_or_new)!=3 : + raise ValueError(u"Format études non valides.") + + new = ['','',''] + for i in range(0,3) : + n = preattr(index_or_new[i])[1] + if n in new or n=='' : + raise ValueError(u"Etudes non valides.") + new[i] = n + + self._set('etudes',new) + + return new def carteEtudiant(self,action=None) : - """ - Action est un entier représentant une année - si positif ajoute l'année à la liste - si négatif le supprime - """ - return self._an('carteEtudiant',action) + """ + Action est un entier représentant une année + si positif ajoute l'année à la liste + si négatif le supprime + """ + return self._an('carteEtudiant',action) def compte(self,login=None,uidNumber=0,hash_pass='',shell=config.login_shell) : - """ - Création d'un compte à un adhérent - (la création se fait après l'écriture dans la base par la méthode save) - Si login = None, retourne le compte de l'adhérent - """ - if not login : - if self.mail().find('@') != -1 : - return '' - else : - return self.mail() - - # Supression des accents et espaces - login = strip_accents(login) - - l, login = preattr(login) - login = login.lower() - - if 'posixAccount' in self._data['objectClass'] : - if login != self._data['uid'] : - # A déja un compte - raise ValueError(u"L'adhérent à déjà un compte. Login : %s" % self._data['uid'][0]) - else : - return login - - for c in login[:]: - if not c in (string.letters + '-') : - raise ValueError(u"Seuls les caractères alphabétiques non accentués et le - sont autorisés dans le login.") - if l<2 : - raise ValueError(u"Login trop court.") - if l>config.maxlen_login : - raise ValueError(u"Login trop long.") - if login[0]=='-' : - raise ValueError(u"- interdit en première position.") - - if mailexist(login) : - raise ValueError(u"Login existant ou correspondant à un alias mail.",1) + """ + Création d'un compte à un adhérent + (la création se fait après l'écriture dans la base par la méthode save) + Si login = None, retourne le compte de l'adhérent + """ + if not login : + if self.mail().find('@') != -1 : + return '' + else : + return self.mail() + + # Supression des accents et espaces + login = strip_accents(login) + + l, login = preattr(login) + login = login.lower() + + if 'posixAccount' in self._data['objectClass'] : + if login != self._data['uid'] : + # A déja un compte + raise ValueError(u"L'adhérent à déjà un compte. Login : %s" % self._data['uid'][0]) + else : + return login + + for c in login[:]: + if not c in (string.letters + '-') : + raise ValueError(u"Seuls les caractères alphabétiques non accentués et le - sont autorisés dans le login.") + if l<2 : + raise ValueError(u"Login trop court.") + if l>config.maxlen_login : + raise ValueError(u"Login trop long.") + if login[0]=='-' : + raise ValueError(u"- interdit en première position.") + + if mailexist(login) : + raise ValueError(u"Login existant ou correspondant à un alias mail.",1) - home = '/home/' + login - if os.path.exists(home) : - raise ValueError(u'Création du compte impossible : home existant',1) - - # Lock du mail - self._locks.append(self.lock('mail',login)) + home = '/home/' + login + if os.path.exists(home) : + raise ValueError(u'Création du compte impossible : home existant',1) + + # Lock du mail + self._locks.append(self.lock('mail',login)) - self._data['mail']= [ login ] - if not 'compte' in self.modifs : - self.modifs.append('compte') - - # Création de l'alias cannonique - if self.nom() and self.prenom() : - a = '%s.%s' % (self.prenom().capitalize(), self.nom().capitalize()) - self.cannonical_alias(a) - - self._data['objectClass'] = [ 'adherent', 'posixAccount', 'shadowAccount' ] - self._data['uid'] = [ login ] - self._data['cn'] = [ preattr(self.Nom())[1] ] - #self._data['shadowLastChange'] = [ '12632' ] - #self._data['shadowMax'] = [ '99999'] - #self._data['shadowWarning'] = [ '7' ] - self._data['loginShell' ] = [ shell ] - if hash_pass : - self._data['userPassword'] = [ hash_pass ] - - if uidNumber : - if self.exist('(uidNumber=%s)' % uidNumber) : - raise ValueError(u'uidNumber pris') - else : - uidNumber = 1000 - while self.exist('(uidNumber=%s)' % uidNumber) : - uidNumber += 1 - try : - self._locks.append(self.lock('uidNumber',str(uidNumber))) - except : - # Quelqu'un nous a piqué l'uid que l'on venait de choisir ! - return self.compte(login,uidNumber,hash_pass,shell) - - self._data['uidNumber']= [ str(uidNumber) ] - self._data['gidNumber']=[ str(config.gid) ] - - self._data['homeDirectory']=[ preattr(home)[1] ] - self._data['gecos'] = [ preattr(strip_accents(self.Nom()))[1] + ',,,' ] - - return decode(login) + self._data['mail']= [ login ] + if not 'compte' in self.modifs : + self.modifs.append('compte') + + # Création de l'alias cannonique + if self.nom() and self.prenom() : + a = '%s.%s' % (self.prenom().capitalize(), self.nom().capitalize()) + self.cannonical_alias(a) + + self._data['objectClass'] = [ 'adherent', 'posixAccount', 'shadowAccount' ] + self._data['uid'] = [ login ] + self._data['cn'] = [ preattr(self.Nom())[1] ] + #self._data['shadowLastChange'] = [ '12632' ] + #self._data['shadowMax'] = [ '99999'] + #self._data['shadowWarning'] = [ '7' ] + self._data['loginShell' ] = [ shell ] + if hash_pass : + self._data['userPassword'] = [ hash_pass ] + + if uidNumber : + if self.exist('(uidNumber=%s)' % uidNumber) : + raise ValueError(u'uidNumber pris') + else : + uidNumber = 1000 + while self.exist('(uidNumber=%s)' % uidNumber) : + uidNumber += 1 + try : + self._locks.append(self.lock('uidNumber',str(uidNumber))) + except : + # Quelqu'un nous a piqué l'uid que l'on venait de choisir ! + return self.compte(login,uidNumber,hash_pass,shell) + + self._data['uidNumber']= [ str(uidNumber) ] + self._data['gidNumber']=[ str(config.gid) ] + + self._data['homeDirectory']=[ preattr(home)[1] ] + self._data['gecos'] = [ preattr(strip_accents(self.Nom()))[1] + ',,,' ] + + return decode(login) def cannonical_alias(self,new=None) : - """ Retourne ou défini l'alias canonique""" - if new == None : - try : return decode(self._data['cannonicalAlias'][0]) - except : return '' - else : - a = strip_accents(new) - a = preattr(a)[1] - - if not mailexist(a) : - # Attribution de l'alias, sinon on passe - - # Lock de cannonicalAlias - self._locks.append(self.lock('cannonicalAlias',a)) - - # Attribution - self._set('cannonicalAlias',[a]) - return a + """ Retourne ou défini l'alias canonique""" + if new == None : + try : return decode(self._data['cannonicalAlias'][0]) + except : return '' + else : + a = strip_accents(new) + a = preattr(a)[1] + + if not mailexist(a) : + # Attribution de l'alias, sinon on passe + + # Lock de cannonicalAlias + self._locks.append(self.lock('cannonicalAlias',a)) + + # Attribution + self._set('cannonicalAlias',[a]) + return a def droits(self,droits=None) : - """ droits est la liste des droits à donner à l'utilisateur """ - if droits==None : - return map(decode,self._data.get('droits',[])) - - if not isadm : - raise EnvironmentError(u'Il faut être administrateur pour effectuer cette opération.') - - if type(droits)!=list : - raise TypeError(u'Une liste est attendue') - - new = [] - for droit in droits : - if droit == '' : continue - droit = unicode(droit.strip(),'iso-8859-15') - if droit not in droits_possibles : - raise ValueError(u'Droit %s incorrect' % droit) - new.append(droit.encode('utf-8')) - - if new != self._data.get('droits',[]) : - self._set('droits',new) - - return new + """ droits est la liste des droits à donner à l'utilisateur """ + if droits==None : + return map(decode,self._data.get('droits',[])) + + if not isadm : + raise EnvironmentError(u'Il faut être administrateur pour effectuer cette opération.') + + if type(droits)!=list : + raise TypeError(u'Une liste est attendue') + + new = [] + for droit in droits : + if droit == '' : continue + droit = unicode(droit.strip(),'iso-8859-15') + if droit not in droits_possibles : + raise ValueError(u'Droit %s incorrect' % droit) + new.append(droit.encode('utf-8')) + + if new != self._data.get('droits',[]) : + self._set('droits',new) + + return new class club(base_proprietaire) : """ Classe de définition d'un club """ @@ -1578,59 +1578,59 @@ class club(base_proprietaire) : def Nom(self,new=None) : """ Défini ou retourne le nom du club """ - if new==None : - return decode(self._data.get('nom',[''])[0]) - - l, new = preattr(new) - new = new.capitalize() - if l<2 : - raise ValueError(u"Nom trop court.") + if new==None : + return decode(self._data.get('nom',[''])[0]) + + l, new = preattr(new) + new = new.capitalize() + if l<2 : + raise ValueError(u"Nom trop court.") - self._set('nom',[new]) - return new + self._set('nom',[new]) + return new def nom(self) : - """ Retourne le nom du club, utilisé lors de la destruction """ - return strip_accents(self.Nom()) + """ Retourne le nom du club, utilisé lors de la destruction """ + return strip_accents(self.Nom()) def carteEtudiant(self,pd=None) : - return [ ann_scol ] + return [ ann_scol ] def responsable(self,adher=None) : - """ Responsable du club, adher doit être une instance de la classe adhérent """ - if adher==None : - aid = decode(self._data.get('responsable',[''])[0]) - if aid : - return self.search('aid=%s' % aid)['adherent'][0] - else : return '' - - if adher.__class__ != adherent : - raise ValueError - - if not adher.id() : - raise AttributeError(u'Adhérent invalide') - - self._set('responsable',[adher.id()]) - return adher + """ Responsable du club, adher doit être une instance de la classe adhérent """ + if adher==None : + aid = decode(self._data.get('responsable',[''])[0]) + if aid : + return self.search('aid=%s' % aid)['adherent'][0] + else : return '' + + if adher.__class__ != adherent : + raise ValueError + + if not adher.id() : + raise AttributeError(u'Adhérent invalide') + + self._set('responsable',[adher.id()]) + return adher def chbre(self,new=None) : - """ Défini le local du club - new doit être une des clefs de l'annuaire locaux_clubs""" - if new==None : - return decode(self._data.get('chbre',[''])[0]) + """ Défini le local du club + new doit être une des clefs de l'annuaire locaux_clubs""" + if new==None : + return decode(self._data.get('chbre',[''])[0]) - annu = annuaires.locaux_clubs() - if new not in annu.keys() : - raise ValueError(u'Local invalide',annu) - - self._set('chbre',[new]) - return new + annu = annuaires.locaux_clubs() + if new not in annu.keys() : + raise ValueError(u'Local invalide',annu) + + self._set('chbre',[new]) + return new def local(self) : - """ Retourne le local à partir de la chambre enregistrée et - de la conversion avec l'annuaire locaux_clubs """ - annu = annuaires.locaux_clubs() - return decode(annu.get(self.chbre(),'')) + """ Retourne le local à partir de la chambre enregistrée et + de la conversion avec l'annuaire locaux_clubs """ + annu = annuaires.locaux_clubs() + return decode(annu.get(self.chbre(),'')) def compte(self,login=None) : """ Créé un compte au club sur zamok""" @@ -1638,331 +1638,331 @@ class club(base_proprietaire) : return self._data.get('uid',[''])[0] # Génération du login : club- - login = login.lower() - if not sre.match('^club-', login) : - login = 'club-' + login - for l in login : - if l not in string.letters + '-': - raise ValueError('Caractère %s interdit dans le login.' % l) - login = preattr(login)[1] - - if 'posixAccount' in self._data['objectClass'] : - if login != self._data['uid'] : - # A déja un compte - raise ValueError(u"Le club à déjà un compte. Login : %s" % self._data['uid'][0]) - else : - return login - - if mailexist(login) and not os.system('/usr/sbin/list_lists | grep -qi %s' % login) : - # la 2ème vérif est pour vérifier que ce n'est pas la ML du club - raise ValueError(u"Login existant ou correspondant à un alias mail.",1) + login = login.lower() + if not sre.match('^club-', login) : + login = 'club-' + login + for l in login : + if l not in string.letters + '-': + raise ValueError('Caractère %s interdit dans le login.' % l) + login = preattr(login)[1] + + if 'posixAccount' in self._data['objectClass'] : + if login != self._data['uid'] : + # A déja un compte + raise ValueError(u"Le club à déjà un compte. Login : %s" % self._data['uid'][0]) + else : + return login + + if mailexist(login) and not os.system('/usr/sbin/list_lists | grep -qi %s' % login) : + # la 2ème vérif est pour vérifier que ce n'est pas la ML du club + raise ValueError(u"Login existant ou correspondant à un alias mail.",1) - home = '/home/' + login.replace('-','/',1) - if os.path.exists(home) : - raise ValueError(u'Création du compte impossible : home existant',1) - - # Lock du mail - self._locks.append(self.lock('mail',login)) + home = '/home/' + login.replace('-','/',1) + if os.path.exists(home) : + raise ValueError(u'Création du compte impossible : home existant',1) + + # Lock du mail + self._locks.append(self.lock('mail',login)) - if not 'compte' in self.modifs : - self.modifs.append('compte') - - self._data['objectClass'] = [ 'club', 'posixAccount', 'shadowAccount' ] - self._data['uid'] = [ login ] - self._data['cn'] = [ preattr(self.Nom())[1] ] - self._data['loginShell' ] = [ config.club_login_shell ] - + if not 'compte' in self.modifs : + self.modifs.append('compte') + + self._data['objectClass'] = [ 'club', 'posixAccount', 'shadowAccount' ] + self._data['uid'] = [ login ] + self._data['cn'] = [ preattr(self.Nom())[1] ] + self._data['loginShell' ] = [ config.club_login_shell ] + # Détermination de l'uid uidNumber = 1000 while self.exist('(uidNumber=%s)' % uidNumber) : uidNumber += 1 - try: - self._locks.append(self.lock('uidNumber',str(uidNumber))) - except : - # Quelqu'un nous a piqué l'uid que l'on venait de choisir ! - return self.compte(login) - - self._data['uidNumber']= [ str(uidNumber) ] - self._data['gidNumber']=[ str(config.club_gid) ] - self._data['homeDirectory']=[ preattr(home)[1] ] - - return decode(login) + try: + self._locks.append(self.lock('uidNumber',str(uidNumber))) + except : + # Quelqu'un nous a piqué l'uid que l'on venait de choisir ! + return self.compte(login) + + self._data['uidNumber']= [ str(uidNumber) ] + self._data['gidNumber']=[ str(config.club_gid) ] + self._data['homeDirectory']=[ preattr(home)[1] ] + + return decode(login) class machine(base_classes_crans) : """ Classe de définition d'une machine """ idn = 'mid' def __init__(self,parent_or_tuple,typ='fixe',conn=None) : - """ - parent_or_tuple est : - *soit une instance d'une classe pouvant posséder une machine - (adherent, club ou crans), la nouvelle machine lui sera alors associé. - *soit directement le tuple définissant une machine (tel que - retourné par les fonctions de recherche ldap) - typ permet de définir le type de machine : wifi ou fixe, - pris en compte uniquement pour une nouvelle machine (parent donné) - - Pour édition d'une machine, typ devra être égal à 'w' - Attention, si typ ='w' mais si l'objet est déja locké il n'y a pas d'erreur - vérifier l'obtetion du lock grace à la valeur de _modifiable (si =w c'est bon) + """ + parent_or_tuple est : + *soit une instance d'une classe pouvant posséder une machine + (adherent, club ou crans), la nouvelle machine lui sera alors associé. + *soit directement le tuple définissant une machine (tel que + retourné par les fonctions de recherche ldap) + typ permet de définir le type de machine : wifi ou fixe, + pris en compte uniquement pour une nouvelle machine (parent donné) + + Pour édition d'une machine, typ devra être égal à 'w' + Attention, si typ ='w' mais si l'objet est déja locké il n'y a pas d'erreur + vérifier l'obtetion du lock grace à la valeur de _modifiable (si =w c'est bon) - conn est une instance de la classe de connexion à la base LDAP - """ - self.conn = conn - if not self.conn : self.connect() - self.modifs=[] - self._locks=[] - t = parent_or_tuple.__class__ - if t == tuple : - # Initialisation avec données fournies - self.dn = parent_or_tuple[0] - if typ == 'w' : - try : - self._locks.append(self.lock(self.idn, self.id())) - self._modifiable = 'w' - except EnvironmentError , c: - self._modifiable = 0 - else : - self._modifiable = 0 - self._init_data = parent_or_tuple[1].copy() # Utile pour construire l'instruction LDAP de modif - self._data = parent_or_tuple[1] - - # Type de machine - if self._init_data.has_key('ipsec') : - self.__typ = 'wifi' - elif self._init_data.has_key('puissance') : - self.__typ = 'borne' - else : - self.__typ = 'fixe' - - # Propriéraire inconnu mais ce n'est pas grave - self.__proprietaire = None - - elif t == adherent or t == club or t == crans and typ in [ 'fixe' , 'wifi' , 'borne' ] : - # Machine vide - self.__proprietaire = parent_or_tuple - self.dn = parent_or_tuple.dn - self._data={ 'objectClass' : [ 'machine' ] } - if typ == 'borne' : - # Valeurs par défaut - self._data['canal'] = '11' - self._data['puissance'] = '33' - self._init_data={} - self.__typ = typ - self._modifiable = 'w' - - chbre = self.__proprietaire.chbre() - # if chbre == 'EXT' and typ == 'fixe' : - # raise ValueError(u'Il faut une chambre pour pouvoir posséder une machine fixe') + conn est une instance de la classe de connexion à la base LDAP + """ + self.conn = conn + if not self.conn : self.connect() + self.modifs=[] + self._locks=[] + t = parent_or_tuple.__class__ + if t == tuple : + # Initialisation avec données fournies + self.dn = parent_or_tuple[0] + if typ == 'w' : + try : + self._locks.append(self.lock(self.idn, self.id())) + self._modifiable = 'w' + except EnvironmentError , c: + self._modifiable = 0 + else : + self._modifiable = 0 + self._init_data = parent_or_tuple[1].copy() # Utile pour construire l'instruction LDAP de modif + self._data = parent_or_tuple[1] + + # Type de machine + if self._init_data.has_key('ipsec') : + self.__typ = 'wifi' + elif self._init_data.has_key('puissance') : + self.__typ = 'borne' + else : + self.__typ = 'fixe' + + # Propriéraire inconnu mais ce n'est pas grave + self.__proprietaire = None + + elif t == adherent or t == club or t == crans and typ in [ 'fixe' , 'wifi' , 'borne' ] : + # Machine vide + self.__proprietaire = parent_or_tuple + self.dn = parent_or_tuple.dn + self._data={ 'objectClass' : [ 'machine' ] } + if typ == 'borne' : + # Valeurs par défaut + self._data['canal'] = '11' + self._data['puissance'] = '33' + self._init_data={} + self.__typ = typ + self._modifiable = 'w' + + chbre = self.__proprietaire.chbre() + # if chbre == 'EXT' and typ == 'fixe' : + # raise ValueError(u'Il faut une chambre pour pouvoir posséder une machine fixe') - if chbre == '????' : - raise ValueError(u'ERREUR : la chambre du propriétaire est inconnue') + if chbre == '????' : + raise ValueError(u'ERREUR : la chambre du propriétaire est inconnue') - if typ == 'wifi' : - # Génération de la clef IPsec - self.ipsec(1) - - else : - raise TypeError(u'Arguments invalides') - + if typ == 'wifi' : + # Génération de la clef IPsec + self.ipsec(1) + + else : + raise TypeError(u'Arguments invalides') + def Nom(self) : - """ Retourne le nom de la machine """ - return self.nom() - + """ Retourne le nom de la machine """ + return self.nom() + def mac(self,mac=None,multi_ok=0) : - """ - Défini ou retourne l'adresse mac de la machine - Adresse valide si : - 12 caractères hexa avec - ou : comme séparateurs - non nulle - Stoque l'adresse sous la forme xx:xx:xx:xx:xx:xx - Si multi_ok = 1 permet d'avoir plusieur fois la même mac sur le réseau - """ - - if mac==None : - return decode(self._data.get('macAddress',[''])[0]) - - mac = format_mac(mac) - - # La mac serait-elle déjà connue ? - if not multi_ok and self.exist('macAddress=%s' % mac) : - raise ValueError(u'Mac déja utilisée sur le réseau.',1) + """ + Défini ou retourne l'adresse mac de la machine + Adresse valide si : + 12 caractères hexa avec - ou : comme séparateurs + non nulle + Stoque l'adresse sous la forme xx:xx:xx:xx:xx:xx + Si multi_ok = 1 permet d'avoir plusieur fois la même mac sur le réseau + """ + + if mac==None : + return decode(self._data.get('macAddress',[''])[0]) + + mac = format_mac(mac) + + # La mac serait-elle déjà connue ? + if not multi_ok and self.exist('macAddress=%s' % mac) : + raise ValueError(u'Mac déja utilisée sur le réseau.',1) # La MAC serait-elle une MAC à la con ? if mac[0].lower() in ['b','c','d','e','f']: raise ValueError(u"L'adresse MAC correspond à un pont réseau, désactivez ce pont réseau.",2) - + # Lock de la mac - self._locks.append(self.lock('macAddress',mac)) + self._locks.append(self.lock('macAddress',mac)) - self._set('macAddress',[mac]) - return mac + self._set('macAddress',[mac]) + return mac def __host_alias(self,champ,new) : - """ Vérification de la validité d'un nom de machine """ - # Supression des accents - new = strip_accents(unicode(new,'iso-8859-15')) - - l, new = preattr(new) - new = new.lower() - l = len(new.split('.')[0]) - - if l<2 : - raise ValueError(u"%s trop court." % champ.capitalize()) - - if self.proprietaire().__class__ != crans : - new = new.split('.',1)[0] - for c in new[:]: - if not c in (string.letters + string.digits + '-') : - raise ValueError(u"Seuls les caractères alphabétiques minuscules et les - sont autorisés pour %s" % champ) - - if l>17 : - raise ValueError(u"%s trop long." % champ.capitalize()) - - if not new[0].isalnum() : - raise ValueError(u"Le premier caractère du champ %s doit être alphanumérique" % champ) - - # Ajout du domaine si necessaire - if new.find('.')==-1 : - try : - new += '.' + config.domains[self.__typ] - except : - raise RuntimeError(u"%s : domaine non trouvé" % champ.capitalize() ) - - # Pas déja pris ? - if self.exist('(|(host=%s)(hostAlias=%s))' % (new,new)) : - raise ValueError(u"%s : nom déjà pris" % champ.capitalize()) - - # Lock host - self._locks.append(self.lock('host',new)) - - return new + """ Vérification de la validité d'un nom de machine """ + # Supression des accents + new = strip_accents(unicode(new,'iso-8859-15')) + + l, new = preattr(new) + new = new.lower() + l = len(new.split('.')[0]) + + if l<2 : + raise ValueError(u"%s trop court." % champ.capitalize()) + + if self.proprietaire().__class__ != crans : + new = new.split('.',1)[0] + for c in new[:]: + if not c in (string.letters + string.digits + '-') : + raise ValueError(u"Seuls les caractères alphabétiques minuscules et les - sont autorisés pour %s" % champ) + + if l>17 : + raise ValueError(u"%s trop long." % champ.capitalize()) + + if not new[0].isalnum() : + raise ValueError(u"Le premier caractère du champ %s doit être alphanumérique" % champ) + + # Ajout du domaine si necessaire + if new.find('.')==-1 : + try : + new += '.' + config.domains[self.__typ] + except : + raise RuntimeError(u"%s : domaine non trouvé" % champ.capitalize() ) + + # Pas déja pris ? + if self.exist('(|(host=%s)(hostAlias=%s))' % (new,new)) : + raise ValueError(u"%s : nom déjà pris" % champ.capitalize()) + + # Lock host + self._locks.append(self.lock('host',new)) + + return new def nom(self,new=None) : - """ - Défini ou retourne le nom de machine. - Un nom de machine valide ne comporte que des caractères - alphabétiques minuscules et le - - """ - if new==None : - return decode(self._data.get('host',[''])[0]) + """ + Défini ou retourne le nom de machine. + Un nom de machine valide ne comporte que des caractères + alphabétiques minuscules et le - + """ + if new==None : + return decode(self._data.get('host',[''])[0]) - new = self.__host_alias('nom de machine',new) - self._set('host',[new]) - return new.split('.')[0] + new = self.__host_alias('nom de machine',new) + self._set('host',[new]) + return new.split('.')[0] def prise(self,new=None) : - """ Retourne ou défini la prise associée à la machine - La définition n'est possible que si la machine est - une machine de l'assoce. - Si la prise est inconne retourne N/A - """ - if new == None : - if self.proprietaire().__class__ == crans : - return decode(self._data.get('prise',['N/A'])[0]) - else : - chbre = self.proprietaire().chbre() - if chbre and chbre[0].lower() in annuaires.chbre_prises.keys() : - try : - return annuaires.chbre_prises[chbre[0].lower()][chbre[1:]] - except : - return 'N/A' - - # Attribution de la prise - new=preattr(new)[1] - if new == 'N/A' : - self._set('prise',[]) - self._data.pop('prise') - return - - if not sre.match('^[a-cg-jmp][0-6][0-5][0-9]$',new.lower()) : - raise ValueError('Prise incorrecte') - - self._set('prise',[new.upper()]) - return new + """ Retourne ou défini la prise associée à la machine + La définition n'est possible que si la machine est + une machine de l'assoce. + Si la prise est inconne retourne N/A + """ + if new == None : + if self.proprietaire().__class__ == crans : + return decode(self._data.get('prise',['N/A'])[0]) + else : + chbre = self.proprietaire().chbre() + if chbre and chbre[0].lower() in annuaires.chbre_prises.keys() : + try : + return annuaires.chbre_prises[chbre[0].lower()][chbre[1:]] + except : + return 'N/A' + + # Attribution de la prise + new=preattr(new)[1] + if new == 'N/A' : + self._set('prise',[]) + self._data.pop('prise') + return + + if not sre.match('^[a-cg-jmp][0-6][0-5][0-9]$',new.lower()) : + raise ValueError('Prise incorrecte') + + self._set('prise',[new.upper()]) + return new def alias(self,new=None) : - """ - Création ou visualisation des alias d'une machine. - Même sytème d'argument que la méthode info. - """ - if not self._data.has_key('hostAlias') : - self._data['hostAlias']=[] - liste = list(self._data['hostAlias']) - if new==None : return map(decode,liste) - - if type(new)==list : - # Modif - index = new[0] - new = new[1] - if new=='' : - liste.pop(index) - self._set('hostAlias',liste) - return liste - else : - index=-1 - - # Test si valide - new = self.__host_alias('alias',new) + """ + Création ou visualisation des alias d'une machine. + Même sytème d'argument que la méthode info. + """ + if not self._data.has_key('hostAlias') : + self._data['hostAlias']=[] + liste = list(self._data['hostAlias']) + if new==None : return map(decode,liste) + + if type(new)==list : + # Modif + index = new[0] + new = new[1] + if new=='' : + liste.pop(index) + self._set('hostAlias',liste) + return liste + else : + index=-1 + + # Test si valide + new = self.__host_alias('alias',new) - if index!=-1 : - liste[index] = new - else : - liste = liste + [ new ] - - self._set('hostAlias',liste) - return liste + if index!=-1 : + liste[index] = new + else : + liste = liste + [ new ] + + self._set('hostAlias',liste) + return liste def ip(self,ip=None) : - """ - Défini ou retourne l'IP de la machine. - Les IP sont stoquées sous forme xxx.xxx.xxx.xxx et doivent être fournies ainsi. - Si l'IP n'est pas définie retourne . - Si ip= attribue la permière IP libre du sous réseau. - """ - if ip==None : - if self._data.has_key('ipHostNumber') : - return decode(self._data['ipHostNumber'][0]) - elif self.proprietaire().__class__ == crans and self.__typ != 'borne': - return '' - else : - return '' - - l, ip = preattr(ip) + """ + Défini ou retourne l'IP de la machine. + Les IP sont stoquées sous forme xxx.xxx.xxx.xxx et doivent être fournies ainsi. + Si l'IP n'est pas définie retourne . + Si ip= attribue la permière IP libre du sous réseau. + """ + if ip==None : + if self._data.has_key('ipHostNumber') : + return decode(self._data['ipHostNumber'][0]) + elif self.proprietaire().__class__ == crans and self.__typ != 'borne': + return '' + else : + return '' + + l, ip = preattr(ip) - # Dans quel réseau la machine doit-elle être placée ? - if self.__typ == 'wifi' : - net = config.NETs['wifi'] - elif self.__typ == 'borne' : - net = config.NETs['bornes'] - elif self.proprietaire().__class__ == crans : - net = [ '0.0.0.0/0' ] - else : - try : - net = config.NETs[self.proprietaire().chbre()[0].lower()] - except : - raise RuntimeError(u'Impossible de trouver le réseau où placer la machine.') - - if ip=='' : + # Dans quel réseau la machine doit-elle être placée ? + if self.__typ == 'wifi' : + net = config.NETs['wifi'] + elif self.__typ == 'borne' : + net = config.NETs['bornes'] + elif self.proprietaire().__class__ == crans : + net = [ '0.0.0.0/0' ] + else : + try : + net = config.NETs[self.proprietaire().chbre()[0].lower()] + except : + raise RuntimeError(u'Impossible de trouver le réseau où placer la machine.') + + if ip=='' : pool_ip = [] # Pool d'IP à tester - for ne in net : - ip = ne.split('/')[0] - ip = ip.split('.') - n=[] - for i in ip : - n.append(int(i)) - while 1 : - if n[3] < 255 : - n[3] += 1 - else : - n[2] += 1 - n[3] = 0 - if n[2]==255 : break + for ne in net : + ip = ne.split('/')[0] + ip = ip.split('.') + n=[] + for i in ip : + n.append(int(i)) + while 1 : + if n[3] < 255 : + n[3] += 1 + else : + n[2] += 1 + n[3] = 0 + if n[2]==255 : break ip = "%d.%d.%d.%d" % tuple(n) if not iptools.AddrInNet(ip,ne): # On est allé trop loin break - pool_ip.append(ip) + pool_ip.append(ip) # On va prendre choisir une IP au hasard dans le pool des IP dispo ip = '' @@ -1973,258 +1973,258 @@ class machine(base_classes_crans) : # On a trouvé la première ip libre break - if ip =='' : - raise RuntimeError(u'Plus d\'IP libres dans %s.' % string.join(net,' et ') ) - - else : - # L'ip est elle dans le bon sous réseau ? - # (accessoirement teste si l'IP est valide et ne correspond pas - # à l'adresse de broadcast ou de réseau) - if not iptools.AddrInNet(ip,net) : - raise ValueError(u'IP invalide ou en dehors du sous réseau alloué.',1) - # Reformatage - ip = iptools.DecToQuad(iptools.QuadToDec(ip)) - # L'ip est-elle déja allouée ? - if self.exist('ipHostNumber=%s' % ip) : - raise ValueError(u'IP déjà prise.') - - # Lock ip - self._locks.append(self.lock('ipHostNumber',ip)) - - self._set('ipHostNumber',[ip]) - return ip + if ip =='' : + raise RuntimeError(u'Plus d\'IP libres dans %s.' % string.join(net,' et ') ) + + else : + # L'ip est elle dans le bon sous réseau ? + # (accessoirement teste si l'IP est valide et ne correspond pas + # à l'adresse de broadcast ou de réseau) + if not iptools.AddrInNet(ip,net) : + raise ValueError(u'IP invalide ou en dehors du sous réseau alloué.',1) + # Reformatage + ip = iptools.DecToQuad(iptools.QuadToDec(ip)) + # L'ip est-elle déja allouée ? + if self.exist('ipHostNumber=%s' % ip) : + raise ValueError(u'IP déjà prise.') + + # Lock ip + self._locks.append(self.lock('ipHostNumber',ip)) + + self._set('ipHostNumber',[ip]) + return ip def proprietaire(self) : - """ - retroune le propriétaire de la machine (classe adherent, club ou crans) - """ - if not self.__proprietaire : - res = self.conn.search_s(','.join(self.dn.split(',')[1:]),0) - if 'adherent' in res[0][1]['objectClass'] : - self.__proprietaire = adherent(res[0],self._modifiable,self.conn) - elif 'club' in res[0][1]['objectClass'] : - self.__proprietaire = club(res[0],self._modifiable,self.conn) - else : - self.__proprietaire = crans() - - return self.__proprietaire - + """ + retroune le propriétaire de la machine (classe adherent, club ou crans) + """ + if not self.__proprietaire : + res = self.conn.search_s(','.join(self.dn.split(',')[1:]),0) + if 'adherent' in res[0][1]['objectClass'] : + self.__proprietaire = adherent(res[0],self._modifiable,self.conn) + elif 'club' in res[0][1]['objectClass'] : + self.__proprietaire = club(res[0],self._modifiable,self.conn) + else : + self.__proprietaire = crans() + + return self.__proprietaire + def ipsec(self,clef=0) : - """ Génération (clef=1) ou affichage de la clef IPsec de la machine - Si clef!=1 : prend la clef fournie. - """ - if self.__typ != 'wifi' : return None - - if not clef : - return decode(self._data.get('ipsec',[''])[0]) - - if clef == 1 : - # Génération - clef = '' - for i in range(12) : - clef += random.choice(string.lowercase + string.digits) - - self._set('ipsec',[clef]) - - return clef + """ Génération (clef=1) ou affichage de la clef IPsec de la machine + Si clef!=1 : prend la clef fournie. + """ + if self.__typ != 'wifi' : return None + + if not clef : + return decode(self._data.get('ipsec',[''])[0]) + + if clef == 1 : + # Génération + clef = '' + for i in range(14) : + clef += random.choice(filter(lambda x: x != 'l', string.lowercase) + + filter(lambda x: x != '1', string.digits)) + + self._set('ipsec',[clef]) + + return clef def canal(self,new=None) : - """ Attribution ou visualisation du canal d'une borne wifi """ - if self.__typ != 'borne' : return None - if not new : - return self._data.get('canal',[''])[0] - - try : - new = int(new) - if new < 0 or new > 14 : raise - except : - raise ValueError(u'Canal invalide : doit être entre 0 et 14') - - self._set('canal',[str(new)]) - return new + """ Attribution ou visualisation du canal d'une borne wifi """ + if self.__typ != 'borne' : return None + if not new : + return self._data.get('canal',[''])[0] + + try : + new = int(new) + if new < 0 or new > 14 : raise + except : + raise ValueError(u'Canal invalide : doit être entre 0 et 14') + + self._set('canal',[str(new)]) + return new def puissance(self,new=None) : - """ Attribution ou visualisation de la puissance d'une borne wifi """ - if self.__typ != 'borne' : return None - if not new : - return self._data.get('puissance',[''])[0] - - try : - new = int(new) - if new < 0 or new > 99 : raise - except : - raise ValueError(u'Puissance invalide : doit être entre 0 et 99') - - self._set('puissance',[str(new)]) - return new + """ Attribution ou visualisation de la puissance d'une borne wifi """ + if self.__typ != 'borne' : return None + if not new : + return self._data.get('puissance',[''])[0] + + try : + new = int(new) + if new < 0 or new > 99 : raise + except : + raise ValueError(u'Puissance invalide : doit être entre 0 et 99') + + self._set('puissance',[str(new)]) + return new def save(self) : - """ - Enregistre la machine courante dans la base LDAP - Retourne une chaîne indiquant les opération effectuées. - """ - if self.proprietaire().__class__ == crans and not isadm : - raise EnvironmentError(u'Il faut être administrateur pour effectuer cette opération.') - - if not self._init_data : - # Nouvelle machine => configuration prise - self.services_to_restart('switch',[self.proprietaire().chbre()]) + """ + Enregistre la machine courante dans la base LDAP + Retourne une chaîne indiquant les opération effectuées. + """ + if self.proprietaire().__class__ == crans and not isadm : + raise EnvironmentError(u'Il faut être administrateur pour effectuer cette opération.') + + if not self._init_data : + # Nouvelle machine => configuration prise + self.services_to_restart('switch',[self.proprietaire().chbre()]) - ret ='' - - # Besoin de redémarrer les firewalls ? - if 'ipHostNumber' in self.modifs or 'macAddress' in self.modifs : - reconf_ip = self._init_data.get('ipHostNumber',[]) - reconf_ip += self._data.get('ipHostNumber',[]) - else : - reconf_ip = [] + ret ='' + + # Besoin de redémarrer les firewalls ? + if 'ipHostNumber' in self.modifs or 'macAddress' in self.modifs : + reconf_ip = self._init_data.get('ipHostNumber',[]) + reconf_ip += self._data.get('ipHostNumber',[]) + else : + reconf_ip = [] # On vire les doublons dans reconf_ip reconf_ip = list(dict(zip(reconf_ip,[None]*len(reconf_ip)))) - - # Enregistrement - self._save() - - # Clef IPsec - if 'ipsec' in self.modifs : - ret += coul(u'Clef IPsec de la machine : %s\n' % self.ipsec(),'cyan') - self.services_to_restart('conf_wifi') + + # Enregistrement + self._save() + + # Clef IPsec + if 'ipsec' in self.modifs : + ret += coul(u'Clef IPsec de la machine : %s\n' % self.ipsec(),'cyan') + self.services_to_restart('conf_wifi') - # Reconfiguration firewalls et dhcps - if reconf_ip : - self.services_to_restart('firewall' , reconf_ip) - self.services_to_restart('firewall-komaz' , reconf_ip) - if self.__typ == 'wifi' : - self.services_to_restart('dhcp-nectaris') + # Reconfiguration firewalls et dhcps + if reconf_ip : + self.services_to_restart('firewall' , reconf_ip) + self.services_to_restart('firewall-komaz' , reconf_ip) + if self.__typ == 'wifi' : + self.services_to_restart('dhcp-nectaris') else: self.services_to_restart('dhcp') - if 'ports' in self.modifs : - self.services_to_restart('firewall-komaz-ports', [ self.ip() ] ) + if 'ports' in self.modifs : + self.services_to_restart('firewall-komaz-ports', [ self.ip() ] ) - # Reconfiguration DNS ? - if 'host' in self.modifs or 'ipHostNumber' in self.modifs or 'hostAlias' in self.modifs : - self.services_to_restart('dns') - - # Reconfiguration bornes wifi ? - if 'canal' in self.modifs or 'puissance' in self.modifs : - self.services_to_restart('bornes_wifi',[self.nom()]) - - # Reconfiguration clients wifi ? - if self.__typ == 'wifi' and ( 'ipHostNumber' in self.modifs or 'host' in self.modifs or 'macAddress' in self.modifs ) : - self.services_to_restart('conf_wifi') - - # Regénération blackliste nécessaire ? - bl = self.blacklist_actif() - if bl and ( 'ipHostNumber' in self.modifs or 'host' in self.modifs ): - for s in bl : - self.services_to_restart(s,[ self.ip() ] ) - - # Regénération de l'autostatus et mail de changmement ? - if self.proprietaire().__class__ == crans : - self.services_to_restart('autostatus') - self.services_to_restart('mail_modification_machine',[self.ip()]) + # Reconfiguration DNS ? + if 'host' in self.modifs or 'ipHostNumber' in self.modifs or 'hostAlias' in self.modifs : + self.services_to_restart('dns') + + # Reconfiguration bornes wifi ? + if 'canal' in self.modifs or 'puissance' in self.modifs : + self.services_to_restart('bornes_wifi',[self.nom()]) + + # Reconfiguration clients wifi ? + if self.__typ == 'wifi' and ( 'ipHostNumber' in self.modifs or 'host' in self.modifs or 'macAddress' in self.modifs ) : + self.services_to_restart('conf_wifi') + + # Regénération blackliste nécessaire ? + bl = self.blacklist_actif() + if bl and ( 'ipHostNumber' in self.modifs or 'host' in self.modifs ): + for s in bl : + self.services_to_restart(s,[ self.ip() ] ) + + # Regénération de l'autostatus et mail de changmement ? + if self.proprietaire().__class__ == crans : + self.services_to_restart('autostatus') + self.services_to_restart('mail_modification_machine',[self.ip()]) - # Remise à zéro - self.modifs=[] - - # Message de sortie - ret += coul(u"Machine %s enregistrée avec succès." % self._data['host'][0],'vert') - - return ret + # Remise à zéro + self.modifs=[] + + # Message de sortie + ret += coul(u"Machine %s enregistrée avec succès." % self._data['host'][0],'vert') + + return ret def delete(self,comment='') : - """ Destruction de la machines """ - if self.proprietaire().__class__ == crans and not isadm : - raise EnvironmentError(u'Il faut être administrateur pour effectuer cette opération.') + """ Destruction de la machines """ + if self.proprietaire().__class__ == crans and not isadm : + raise EnvironmentError(u'Il faut être administrateur pour effectuer cette opération.') - - self.proprio = self.__proprietaire.Nom() # On met dans un coin le nom du proprio - self.__proprietaire = None # On oublie le propriétaire - self._delete(self.dn,comment) + + self.proprio = self.__proprietaire.Nom() # On met dans un coin le nom du proprio + self.__proprietaire = None # On oublie le propriétaire + self._delete(self.dn,comment) - # Services à redémarrer - if self.__typ == 'wifi' : - self.services_to_restart('conf_wifi') - self.services_to_restart('dhcp-nectaris') + # Services à redémarrer + if self.__typ == 'wifi' : + self.services_to_restart('conf_wifi') + self.services_to_restart('dhcp-nectaris') else: self.services_to_restart('dhcp') - - self.services_to_restart('dns') - self.services_to_restart('firewall',[ self.ip() ]) - self.services_to_restart('firewall-komaz',[ self.ip() ]) - + + self.services_to_restart('dns') + self.services_to_restart('firewall',[ self.ip() ]) + self.services_to_restart('firewall-komaz',[ self.ip() ]) + def portTCPin(self,ports=None) : - """ Ports TCP ouverts depuis l'extérieur pour la machine """ - return self.__port(ports,'portTCPin') + """ Ports TCP ouverts depuis l'extérieur pour la machine """ + return self.__port(ports,'portTCPin') def portTCPout(self,ports=None) : - """ Ports TCP ouverts vers l'extérieur pour la machine """ - return self.__port(ports,'portTCPout') + """ Ports TCP ouverts vers l'extérieur pour la machine """ + return self.__port(ports,'portTCPout') def portUDPin(self,ports=None) : - """ Ports UDP ouverts vers l'extérieur pour la machine """ - return self.__port(ports,'portUDPin') + """ Ports UDP ouverts vers l'extérieur pour la machine """ + return self.__port(ports,'portUDPin') def portUDPout(self,ports=None) : - """ Ports UDP ouverts vers l'extérieur pour la machine """ - return self.__port(ports,'portUDPout') - + """ Ports UDP ouverts vers l'extérieur pour la machine """ + return self.__port(ports,'portUDPout') + def __port(self,ports,champ): - if ports == None : - return self._data.get(champ,[''])[0] - - ports = preattr(ports)[1] - if ports and self._data.get(champ)!=ports : - self._data[champ] = [ ports ] - if 'ports' not in self.modifs : - self.modifs.append('ports') - elif self._data.has_key(champ) : - self._data.pop(champ) - if 'ports' not in self.modifs : - self.modifs.append('ports') - + if ports == None : + return self._data.get(champ,[''])[0] + + ports = preattr(ports)[1] + if ports and self._data.get(champ)!=ports : + self._data[champ] = [ ports ] + if 'ports' not in self.modifs : + self.modifs.append('ports') + elif self._data.has_key(champ) : + self._data.pop(champ) + if 'ports' not in self.modifs : + self.modifs.append('ports') + class crans(crans_ldap) : """ Classe définissant l'assoce (pour affichage de ses machines) """ idn = '' def __init__(s,conn=None): - s.conn = conn - if not s.conn : s.connect() - s.dn = s.base_dn + s.conn = conn + if not s.conn : s.connect() + s.dn = s.base_dn def id(s) : - return '' + return '' def Nom(s) : - return u"Crans" + return u"Crans" def chbre(s) : - return u"CRA" + return u"CRA" def blacklist(s) : - return [] + return [] def paiement(s) : - return [ ann_scol ] + return [ ann_scol ] def carteEtudiant(s) : - return [ ann_scol ] + return [ ann_scol ] def blacklist_actif(s) : - return [] + return [] def machines(s) : - res = s.conn.search_s(s.dn,1,'objectClass=machine') - m = [] - for r in res : - m.append(machine(r,'',s.conn)) - return m - + res = s.conn.search_s(s.dn,1,'objectClass=machine') + m = [] + for r in res : + m.append(machine(r,'',s.conn)) + return m + if __name__ == '__main__' : import sys if 'lock' in sys.argv : - db = crans_ldap() - print db.list_locks() + db = crans_ldap() + print db.list_locks() if 'purgelock' in sys.argv : - db = crans_ldap() - db.remove_lock('*') + db = crans_ldap() + db.remove_lock('*') if 'menage' in sys.argv : - print "Ménage des machines des adhérents partis..." - db = crans_ldap() - machines=db.search('paiement!=%s&host=*.crans.org' % ann_scol ,'w')['machine'] - print "Destruction de %i machines" % len(machines) - for m in machines : - print 'Destruction de %s' % m.nom() - m.delete('Ménage') - + print "Ménage des machines des adhérents partis..." + db = crans_ldap() + machines=db.search('paiement!=%s&host=*.crans.org' % ann_scol ,'w')['machine'] + print "Destruction de %i machines" % len(machines) + for m in machines : + print 'Destruction de %s' % m.nom() + m.delete('Ménage')