#! /usr/bin/env python # -*- coding: utf-8 -*- import sys, signal, os import getopt # Imports pour LDAP sys.path.append('/usr/scripts/gestion') from config import droits_groupes, droits_mailing_listes from gen_confs import gen_config, anim, cprint, OK, ERREUR from ldap_crans import crans_ldap, preattr, ldap, CransLdap, strip_accents try: sys.path.append('/usr/lib/mailman') from Mailman import MailList from Mailman import Utils from Mailman.UserDesc import UserDesc except: # Machine sans mailman, les ML ne seront pas reconfigurées pass class droits(gen_config) : def restart(s) : # Rien à faire pass def __str__(s): return "droits" class droits_ldap(CransLdap, droits): ####### Les groupes base_group_dn = 'ou=Group,dc=crans,dc=org' def build_group(self) : """ Reconstruit les groupes dans la base LDAP """ self.anim.iter = len(droits_groupes.keys() ) for group, fonctions in droits_groupes.items() : self.anim.cycle() # Qui doit être dans ce groupe ? res = [] for f in fonctions : res += self.search('droits=%s' % f)['adherent'] # Récupération de la constitution du groupe actuel dn = 'cn=%s,%s' % (group, self.base_group_dn) data = self.conn.search_s(dn ,0,'objectClass=posixGroup')[0][1] init_data = data.copy() # Supression de tout les membres data['memberUid'] = [] # Ajout des bonnes personnes for adher in res : if not adher.droitsGeles(): uid = preattr(adher.compte())[1] if uid and uid not in data['memberUid'] : data['memberUid'].append(uid) if group == 'adm': # Ajout de logcheck et d'arpwatch data['memberUid'].append('logcheck') data['memberUid'].append('arpwatch') elif group == 'webradio': # Ajout de michel et webradio data['memberUid'].append('michel') data['memberUid'].append('webradio') # Sauvegarde modlist = ldap.modlist.modifyModlist(init_data,data) self.conn.modify_s(dn,modlist) def print_liste(self,poste) : """ Donne la liste des membres actifs """ for adh in self.search('droits=%s&chbre!=EXT' % poste)['adherent'] : print "%s %s" % (adh.nom(), adh.prenom()) def config_ML(self, mode='autosync', args=None) : """ Reconfigure les MLs. mode désigne le mode de fonctionnement : * autosync est le mode par défaut, il resynchronise les MLs avec les droits * forcedel fait comme autosync, en demandant un args du type [('ml1', 'all'), ('ml2', 'adresse_mail1')] et supprime les adresses mail concernées de la mailing-liste, 'all' pour toutes les MLs ne correspondant pas à des gens avec des droits (seulement si elles ne seront pas réinscrites automatiquement) * getunsync retourne les gens qui devraient être inscrits/désinscrits de chaque ML args désigne l'argument au mode choisi.""" try: self.anim.iter = len(droits_mailing_listes.keys()) except: pass if mode == 'getunsync': unsync = {} for ML, fonctions in droits_mailing_listes.items() : try: self.anim.cycle() except: pass if ML[0] == '+' : ML = ML[1:] only_add = True else : only_add = False # Instance correspondant à la ML mlist = MailList.MailList(ML) self.mlist_to_unlock = mlist # Qui doit être dans cette ML ? res = [] for f in fonctions : res += self.search('droits=%s' % f)['adherent'] # Liste des personnes déja inscrites deja_inscrits = {} # { email en miniscules : email avec case n'importe comment } for addr in mlist.getMemberCPAddresses(mlist.getMembers()): deja_inscrits[addr.lower()] = addr # Mails à ajouter to_add = [] mail_traite = [] for adher in res : mail = adher.mail().lower() if mail in mail_traite : continue mail_traite.append(mail) if adher._data.get('uid', '') != '' and not mail.endswith('@crans.org') : mail += '@crans.org' if mail not in deja_inscrits.keys() : # Visiblement pas inscrit to_add.append([ mail, adher.Nom() ]) else : # L'adhérent est déja inscrit deja_inscrits.pop(mail) if mode == 'autosync' or mode == 'forcedel': # Ajout for mail, nom in to_add : pw = Utils.MakeRandomPassword() userdesc = UserDesc(mail, strip_accents(nom), pw) mlist.ApprovedAddMember(userdesc) if not only_add or mode == 'forcedel': # Supression des personnes inscritees en trop if not only_add or (mode == 'forcedel' and args != None and (ML, 'all') in args): for mail in deja_inscrits.values() : mlist.ApprovedDeleteMember(mail) else: # Suppression des mails demandés for mail in deja_inscrits.values() : if (ML, mail) in args: mlist.ApprovedDeleteMember(mail) mlist.Save() elif mode == 'getunsync': if to_add or deja_inscrits: unsync[ML] = (only_add, map(lambda (x,y): y, to_add), deja_inscrits.values()) mlist.Unlock() self.mlist_to_unlock = None if mode == 'getunsync': return unsync def gen_conf(self): self.anim = anim('\tconfiguration groupes') try: self.build_group() self.anim.reinit() print OK except: self.anim.reinit() print ERREUR if self.debug : import traceback traceback.print_exc() self.anim = anim('\tconfiguration ML Crans') try: self.config_ML() self.anim.reinit() print OK except: self.anim.reinit() print ERREUR if self.debug : import traceback traceback.print_exc() try: # Au cas où... self.mlist_to_unlock.Unlock() except : pass class desabonner_ml(droits_ldap): def gen_conf(self): self.anim = anim('\tdesabonnement MLs Crans') try: to_del = [] for arg in self.args: (mail, ml) = arg.split('$') to_del.append((ml, "%s@crans.org" % mail)) self.config_ML(mode='forcedel', args=to_del) self.anim.reinit() print OK except: self.anim.reinit() print ERREUR if self.debug : import traceback traceback.print_exc() class droits_openbsd(droits) : def build_master_passwd_group(self) : """Reconstruit les entrées à ajouter dans master.passwd Reconstruit également /etc/group pour le group wheel """ master = "" group = "wheel:*:0:root" self.anim.iter = 2 for fonction in ("Nounou", "Apprenti"): self.anim.cycle() # Qui doit être dans ce groupe ? res = crans_ldap().search('droits=%s' % fonction)['adherent'] for a in res: if fonction == "Nounou": # On rajoute à /etc/group group = "%s,%s" % (group, a._data['uid'][0]) #On conserve le shell #Il faut ôter les emplacements spécifique à linux (type #/usr/bin/zsh) if "zsh" in a._data['loginShell'][0]: shell = "/bin/zsh" elif "bash" in a._data['loginShell'][0]: shell = "/bin/bash" else: shell = "/bin/zsh" # On ajoute dans master # Le mot de passe est bidon master = "%s%s:$1$rQcJgpD8$ZZjjszWKnSp9rR6iZ9GPm2:%s:1000:ldap:0:0:%s:%s:%s\n" % (master, a._data['uid'][0], a._data['uidNumber'][0], a._data['gecos'][0], a._data['homeDirectory'][0], shell) group = "%s\n" % group # On va réécrire /etc/master.passwd # cf man master.passwd fichier = file("/etc/master.passwd") for line in fichier: if line.split(":")[4].strip() != "ldap": master = "%s%s" % (line,master) fichier.close() # On va écrire par-dessus fichier = file("/etc/master.passwd", "w") fichier.write(master) fichier.close() os.system("pwd_mkdb -p /etc/master.passwd") # On réécrit /etc/group fichier = file("/etc/group") for line in fichier: if line.split(":")[0].strip() != "wheel": group = "%s%s" % (group,line) fichier.close() # On va réécrire par-dessus fichier = file("/etc/group", "w") fichier.write(group) fichier.close() def gen_conf(self) : self.anim = anim('\tconfiguration master.passwd') try: self.build_master_passwd_group() self.anim.reinit() print OK except: self.anim.reinit() print ERREUR if self.debug : import traceback traceback.print_exc() def usage(): print "%s [options] [arguments]" % sys.argv[0] print "Options :" print " * -h : afficher cette aide" print " * -d ml1:mail1,mail2 ml2:all : enlever des adresses mail" print " * -p droit1 droit2 : afficher les membres ayant tels droits" print " * -u : affiche les MLs avec des gens à inscrire / enlever" if __name__ == '__main__' : try: opts, args = getopt.getopt(sys.argv[1:], "dhpu", []) except: usage() sys.exit() if len(opts) == 0 or '-h' in sys.argv[1:]: usage() sys.exit() cl = droits_ldap() for o, a in opts: if o == '-d': # Suppression d'adresses mail to_del = [] for arg in args: if ':' in arg: [ml, mails] = arg.split(':', 1) to_del.extend(map(lambda m: (ml, m), mails.split(','))) print "Suppression forcée : %s ..." % str(to_del) cl.config_ML(mode='forcedel', args=to_del) elif o == '-p': # Affichage des membres ayant certains droits for arg in args: titre = "%s : " % arg print titre print "-" * len (titre) cl.print_liste(arg) elif o == '-u': # Affichage des MLs non synchronisées print "MLs non synchronisées :" unsync = cl.config_ML(mode='getunsync') for ml in unsync.keys(): (only_add, to_add, to_del) = unsync[ml] print u"%s: À ajouter: %s / À enlever: %s%s" % (ml, ', '.join(to_add), ','.join(to_del), u" (ne seront pas enlevées automatiquement)" if to_add == 1 else "")