def setPPolicyAttribute(self, nameattribute, value): """ Set the value of the given LDAP attribute. Del the attribute if value is None @param nameattribute: LDAP attribute name @type nameattribute: str @param value: LDAP attribute value @type value: str """ if value != None: r = AF().log( PLUGIN_NAME, AA.PPOLICY_MOD_USER_ATTR, [(self.dn, AT.USER), (nameattribute, AT.ATTRIBUTE)], value ) if type(value) == bool: value = str(value).upper() elif type(value) == int: value = str(value) mode = ldap.MOD_REPLACE logging.getLogger().debug("Setting %s to %s" % (nameattribute, value)) else: r = AF().log( PLUGIN_NAME, AA.PPOLICY_DEL_USER_ATTR, [(self.dn, AT.USER), (nameattribute, AT.ATTRIBUTE)], value ) mode = ldap.MOD_DELETE logging.getLogger().debug("Removing %s" % nameattribute) try: self.l.modify_s(self.dn, [(mode, nameattribute, value)]) except ldap.UNDEFINED_TYPE: logging.getLogger().error("Attribute %s isn't defined on LDAP" % nameattribute) except ldap.INVALID_SYNTAX: logging.getLogger().error("Invalid Syntax from the attribute value of %s on ldap" % nameattribute) r.commit()
def delBlacklist(self, elt): """Remove an element from the blacklist""" r = AF().log(PLUGIN_NAME, AA.PROXY_DEL_BLACKLIST, [(elt, AT.BLACKLIST)]) if elt in self.contentArr: self.contentArr.remove(elt) self.saveBlacklist() r.commit()
def setSubnetStatement(self, subnet, option, value = None): r = AF().log(PLUGIN_NAME, AA.NETWORK_SET_SUBNET_STMT, [(subnet, AT.SUBNET), (option, "OPTION")], value) subnets = self.getSubnet(subnet) if subnets: subnetDN = subnets[0][0] self.setObjectStatement(subnetDN, option, value) r.commit()
def updatePPolicy(self, ppolicyName): """ Update the pwdPolicySubentry attribute of the current user """ if self.hasPPolicy(): if not ppolicyName: return self.removePPolicy() else: # get the ppolicy dn ppolicyDN = PPolicy().getPPolicy(ppolicyName)[0] r = AF().log(PLUGIN_NAME, AA.PPOLICY_MOD_USER_PPOLICY, [(self.dn, AT.USER)]) try: self.l.modify_s(self.dn, [(ldap.MOD_REPLACE, "pwdPolicySubentry", ppolicyDN)]) except ldap.UNDEFINED_TYPE: logging.getLogger().error("Attribute %s isn't defined on ldap" % "pwdPolicySubentry") except ldap.INVALID_SYNTAX: logging.getLogger().error( "Invalid Syntax from the attribute value of %s on ldap" % "pwdPolicySubentry" ) r.commit() return True else: return self.addPPolicy(ppolicyName) return False
def disableUser(self, uid): """ Disable the SAMBA user """ userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.SAMBA_DISABLE_USER, [(userdn, AT.USER)]) s = self.l.search_s(userdn, ldap.SCOPE_BASE) c, old = s[0] new = old.copy() flags = new["sambaAcctFlags"][0] # flags should be something like "[U ]" flags = flags.strip("[]") flags = flags.strip() if flags.startswith("D"): # Huh ? User has been already disabled # Do nothing pass else: flags = "D" + flags flags = "[" + flags.ljust(11) + "]" new["sambaAcctFlags"] = [flags] modlist = ldap.modlist.modifyModlist(old, new) self.l.modify_s(userdn, modlist) r.commit() return 0
def setSubnetAuthoritative(self, subnet, flag = True): """ Set the subnet as authoritative or 'not authoritative' @param subnet: the network address of the subnet @type subnet: str @param flag: whether the subnet is authoritative or not @type flag: bool """ r = AF().log(PLUGIN_NAME, AA.NETWORK_SET_SUBNET_AUTH, [(subnet, AT.SUBNET)], flag) subnets = self.getSubnet(subnet) if subnets: subnetDN = subnets[0][0] options = self.getObjectStatements(subnetDN) newoptions = [] for option in options: if not option in ["authoritative", "not authoritative"]: newoptions.append(option) if flag: newoptions.append("authoritative") else: newoptions.append("not authoritative") self.l.modify_s(subnetDN, [(ldap.MOD_REPLACE, "dhcpStatements", newoptions)]) r.commit()
def setZarafaGroup(self, group, value): """ @param group: group name @type group: str @param value: to set or unset the zarafa-group class @type value: boolean Set/unset zarafa-group object class to a user group """ if value: event = AA.MAIL_ADD_ZARAFA_CLASS else: event = AA.MAIL_DEL_ZARAFA_CLASS r = AF().log(PLUGIN_NAME, event, [(group, AT.MAIL_GROUP)], group) group = group.encode("utf-8") cn = 'cn=' + group + ', ' + self.baseGroupsDN attrs = [] attrib = self.l.search_s(cn, ldap.SCOPE_BASE) c, attrs = attrib[0] newattrs = copy.deepcopy(attrs) if value and not 'zarafa-group' in newattrs['objectClass']: newattrs["objectClass"].append('zarafa-group') elif not value and 'zarafa-group' in newattrs['objectClass']: newattrs["objectClass"].remove('zarafa-group') mlist = ldap.modlist.modifyModlist(attrs, newattrs) if mlist: self.l.modify_s(cn, mlist) r.commit()
def setPasswdExpiration(self, uid, can_expire=False): """ Set password expiration flag on SAMBA user """ userdn = self.searchUserDN(uid) action = AA.SAMBA_UNEXPIRE_USER_PASSWD if can_expire: action = AA.SAMBA_EXPIRE_USER_PASSWD s = self.l.search_s(userdn, ldap.SCOPE_BASE) c, old = s[0] new = old.copy() changed = False flags = new["sambaAcctFlags"][0] # flags should be something like "[U ]" if can_expire and 'X' in flags: flags = flags.strip("[]") flags = flags.strip().replace('X', '') flags = "[" + flags.ljust(11) + "]" changed = True elif not can_expire and not 'X' in flags: flags = flags.strip("[]").strip() flags = flags + "X" flags = "[" + flags.ljust(11) + "]" changed = True # If the flag was changed if changed: r = AF().log(PLUGIN_NAME, action, [(userdn, AT.USER)]) new["sambaAcctFlags"] = [flags] modlist = ldap.modlist.modifyModlist(old, new) self.l.modify_s(userdn, modlist) r.commit() return True
def backupShare(share, media, login): """ Launch as a background process the backup of a share """ r = AF().log(PLUGIN_NAME, AA.SAMBA_BACKUP_SHARE, [(share, AT.SHARE), (login, AT.USER)], media) config = BasePluginConfig("base") cmd = os.path.join(config.backuptools, "backup.sh") if share == "homes": # FIXME: Maybe we should have a configuration directive to tell that # all users home are stored into /home savedir = "/home/" else: smbObj = SambaConf(SambaConfig("samba").samba_conf_file) savedir = smbObj.getContent(share, "path") # Run backup process in background shlaunchBackground( cmd + " " + share + " " + savedir + " " + config.backupdir + " " + login + " " + media + " " + config.backuptools, "backup share " + share, progressBackup, ) r.commit() return os.path.join(config.backupdir, "%s-%s-%s" % (login, share, strftime("%Y%m%d")))
def addBlacklist(self, elt): """Add an element to the blacklist""" r = AF().log(PLUGIN_NAME, AA.PROXY_ADD_BLACKLIST, [(elt, AT.BLACKLIST)]) if not elt in self.contentArr: self.contentArr.append(elt) self.saveBlacklist() r.commit()
def setAttribute(self, nameattribute, value, ppolicyName=None): """ Set value to the given attribute. @param nameattribute: LDAP attribute name @type nameattribute: str @param value: LDAP attribute value @type value: str """ if not ppolicyName: ppolicyDN = self.configPPolicy.ppolicydefaultdn else: ppolicyDN = "cn=" + ppolicyName + "," + self.configPPolicy.ppolicydn r = AF().log(PLUGIN_NAME, AA.PPOLICY_MOD_ATTR, [(ppolicyDN, AT.PPOLICY), (nameattribute, AT.ATTRIBUTE)], value) if value != None: if type(value) == bool: value = str(value).upper() elif type(value) == int: value = str(value) try: self.l.modify_s(ppolicyDN, [(ldap.MOD_REPLACE, nameattribute, value)]) except ldap.UNDEFINED_TYPE: logging.getLogger().error("Attribute %s isn't defined on ldap" % nameattribute) except ldap.INVALID_SYNTAX: logging.getLogger().error("Invalid Syntax from the attribute value of %s on ldap" % nameattribute) r.commit()
def setSubnetNetmask(self, subnet, netmask): r = AF().log(PLUGIN_NAME, AA.NETWORK_SET_SUBNET_NTMSK, [(subnet, AT.SUBNET)], netmask) subnets = self.getSubnet(subnet) if subnets: subnetDN = subnets[0][0] self.l.modify_s(subnetDN, [(ldap.MOD_REPLACE, "dhcpNetMask", netmask)]) r.commit()
def addSmbAttr(self, uid, password): """ Add SAMBA password and attributes on a new user """ # Get domain info domainInfo = self.getDomain() # Get current user entry userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.SAMBA_ADD_SAMBA_CLASS, [(userdn,AT.USER)]) s = self.l.search_s(userdn, ldap.SCOPE_BASE) c, old = s[0] new = self._applyUserDefault(old.copy(), self.configSamba.userDefault) if not "sambaSamAccount" in new['objectClass']: new['objectClass'].append("sambaSamAccount") new["sambaAcctFlags"] = ["[U ]"] new["sambaSID"] = [domainInfo['sambaSID'][0] + '-' + str(int(domainInfo['sambaNextRid'][0]) + 1)] # If the passwd has been encoded in the XML-RPC stream, decode it if isinstance(password, xmlrpclib.Binary): password = str(password) # If the passwd is in a dict # {'scalar': 'thepassword', 'xmlrpc_type': 'base64'} # take scalar if isinstance(password, dict): password = password['scalar'] new['sambaLMPassword'] = [smbpasswd.lmhash(password)] new['sambaNTPassword'] = [smbpasswd.nthash(password)] new['sambaPwdLastSet'] = [str(int(time()))] # Update LDAP modlist = ldap.modlist.modifyModlist(old, new) self.l.modify_s(userdn, modlist) self.updateDomainNextRID() self.runHook("samba.addsmbattr", uid, password) r.commit()
def delZone(self, zone): """ Delete a DNS zone with all its reverse zones @param name: the zone name to delete """ r = AF().log(PLUGIN_NAME, AA.NETWORK_DEL_DNS_ZONE, [(zone, AT.ZONE)]) if self.pdns: zoneDN = "dc=" + zone + "," + self.configDns.dnsDN self.delRecursiveEntry(zoneDN) reverseDN = self.getReverseZone(zone) if reverseDN[0]: self.delRecursiveEntry("dc=" + reverseDN[0] + "," + self.configDns.dnsDN) else: zoneDN = "ou=" + zone + "," + self.configDns.dnsDN self.delRecursiveEntry(zoneDN) os.unlink(os.path.join(self.configDns.bindLdapDir, zone)) newcontent = [] f = open(self.configDns.bindLdap, "r") for line in f: if not "/" + zone + '";' in line: newcontent.append(line) f.close() f = open(self.configDns.bindLdap, "w+") for line in newcontent: f.write(line) f.close() r.commit()
def changeUserPasswd(self, uid, passwd, oldpasswd = None, bind = False): """ change SAMBA user password @param uid: user name @type uid: str @param passwd: non encrypted password @type passwd: str """ # Don't update the password if we are using smbk5passwd conf = SambaConf() if conf.isValueTrue(conf.getContent("global", "ldap passwd sync")) in (0, 1): userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.SAMBA_CHANGE_USER_PASS, [(userdn,AT.USER)]) # If the passwd has been encoded in the XML-RPC stream, decode it if isinstance(passwd, xmlrpclib.Binary): passwd = str(passwd) s = self.l.search_s(userdn, ldap.SCOPE_BASE) c, old = s[0] new = old.copy() new['sambaLMPassword'] = [smbpasswd.lmhash(passwd)] new['sambaNTPassword'] = [smbpasswd.nthash(passwd)] new['sambaPwdLastSet'] = [str(int(time()))] # Update LDAP modlist = ldap.modlist.modifyModlist(old, new) self.l.modify_s(userdn, modlist) self.runHook("samba.changeuserpasswd", uid, passwd) r.commit() return 0
def setHostHWAddress(self, subnet, host, address): r = AF().log(PLUGIN_NAME, AA.NETWORK_SET_HOST_HWADD, [(subnet, AT.SUBNET),(host, AT.HOST)], address) hosts = self.getHost(subnet, host) if hosts: hostDN = hosts[0][0] self.l.modify_s(hostDN, [(ldap.MOD_REPLACE, "dhcpHWAddress", ["ethernet " + address])]) r.commit()
def setHostStatement(self, subnet, host, option, value): r = AF().log(PLUGIN_NAME, AA.NETWORK_SET_HOST_STMT, [(subnet, AT.SUBNET),(host, AT.HOST), (option,"OPTION")], value) hosts = self.getHost(subnet, host) if hosts: hostDN = hosts[0][0] self.setObjectStatement(hostDN, option, value) r.commit()
def setPoolRange(self, pool, start, end): r = AF().log(PLUGIN_NAME, AA.NETWORK_SET_POOLRANGE, [(pool, AT.POOL)]) pools = self.getPool(pool) if pools: poolDN = pools[0][0] self.l.modify_s(poolDN, [(ldap.MOD_REPLACE, "dhcpRange", start + " " + end)]) r.commit()
def delHost(self, subnet, hostname): r = AF().log(PLUGIN_NAME, AA.NETWORK_DEL_HOST, [(subnet, AT.SUBNET)], hostname) hosts = self.getHost(subnet, hostname) for host in hosts: if host[1]["cn"][0] == hostname: self.delRecursiveEntry(host[0]) break r.commit()
def removeMail(self, uid): r = AF().log(PLUGIN_NAME, AA.MAIL_DEL_MAIL_CLASS, [(uid, AT.MAIL)]) self.removeUserObjectClass(uid, "mailAccount") r.commit() if self.hasZarafaSupport(): r = AF().log(PLUGIN_NAME, AA.MAIL_DEL_ZARAFA_CLASS, [(uid, AT.MAIL)]) self.removeUserObjectClass(uid, "zarafa-user") r.commit()
def delSubnet(self, network): r = AF().log(PLUGIN_NAME, AA.NETWORK_DEL_SUBNET, [(network, AT.SUBNET)]) subnets = self.getSubnet() for subnet in subnets: if subnet[1]["cn"][0] == network: self.delRecursiveEntry(subnet[0]) break r.commit()
def cleanUp(self): """ function call before shutdown of reactor """ logger.info('mmc-agent shutting down, cleaning up...') l = AuditFactory().log(u'MMC-AGENT', u'MMC_AGENT_SERVICE_STOP') l.commit() self.cleanPid()
def modifyRecord(self, zone, hostname, ip): """ Change the IP address of a host in a zone. If the new IP already exists, an exception is raised. """ r = AF().log(PLUGIN_NAME, AA.NETWORK_MODIFY_RECORD, [(zone, AT.ZONE), (hostname, AT.RECORD_A)], ip) if self.ipExists(zone, ip): raise "The IP %s has been already registered in zone %s" % (ip, zone) self.delRecord(zone, hostname) self.addRecordA(zone, hostname, ip) r.commit()
def setSubnetDescription(self, subnet, description): r = AF().log(PLUGIN_NAME, AA.NETWORK_SET_SUBNET_DESC, [(subnet, AT.SUBNET)], description) subnets = self.getSubnet(subnet) if subnets: subnetDN = subnets[0][0] if description: self.l.modify_s(subnetDN, [(ldap.MOD_REPLACE, "dhcpComments", description)]) else: self.l.modify_s(subnetDN, [(ldap.MOD_DELETE, "dhcpComments", None)]) r.commit()
def delVDomain(self, domain): """ Del a virtual mail domain name entry from directory @param domain: virtual mail domain name @type domain: str """ r = AF().log(PLUGIN_NAME, AA.MAIL_DEL_VDOMAIN, [(domain, AT.VMDOMAIN)]) dn = "virtualdomain=" + domain + ", " + self.conf.vDomainDN self.delRecursiveEntry(dn) r.commit()
def addHostToSubnet(self, subnet, hostname): r = AF().log(PLUGIN_NAME, AA.NETWORK_ADD_HOST_TO_SUB, [(subnet, AT.SUBNET)], hostname) subnets = self.getSubnet(subnet) dn = "cn=" + hostname + "," + subnets[0][0] entry = { "cn" : hostname, "objectClass" : ["top", "dhcpHost", "dhcpOptions"] } attributes=[ (k,v) for k,v in entry.items() ] self.l.add_s(dn, attributes) r.commit()
def dnsService(command): if command != 'status': event = { 'start' : AA.NETWORK_START_DNS_SERVICE, 'stop' : AA.NETWORK_STOP_DNS_SERVICE, 'restart' : AA.NETWORK_RESTART_DNS_SERVICE, 'reload' : AA.NETWORK_RELOAD_DNS_SERVICE } r = AF().log(PLUGIN_NAME, event[command]) ret = DnsService().command(command) if command != 'status': r.commit() return ret
def delSmbAttr(self, uid): """ Remove SAMBA attributes @param uid: username @type uid: str @return: boolean """ userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.SAMBA_DEL_SAMBA_CLASS, [(userdn,AT.USER)]) r.commit() return self.removeUserObjectClass(uid, "sambaSamAccount")
def resetUsersVDomainQuota(self, domain): """ Reset the quota of all users in the given virtual mail domain @param domain: virtual mail domain name @type domain: str """ r = AF().log(PLUGIN_NAME, AA.MAIL_RESET_DOMAIN_QUOTA, [(domain, AT.VMDOMAIN)]) vdomain = self.getVDomain(domain) mailuserquota = vdomain[0][1][self.conf.attrs['mailuserquota']][0] for user in self.getVDomainUsers(domain): self.changeUserAttributes(user[1]["uid"][0], self.conf.attrs['mailuserquota'], mailuserquota, False) r.commit()
def delMachine(self, uid): """ Remove a computer account from LDAP @param uid: computer name @type uid: str """ name='uid=' + uid + ',' + self.baseComputersDN r = AF().log(PLUGIN_NAME, AA.SAMBA_DEL_MACHINE, [(name, AT.MACHINE)]) uid = uid + "$" self.l.delete_s('uid=' + uid + ',' + self.baseComputersDN) r.commit() return 0
def changeMailproxy(self, uid, mailproxy): """ Change the user mailproxy attribute (mail delivery server). @param uid: user name @type uid: str @param mailproxy: the FQDN or IP of the mail server @type mailproxy: str """ userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.MAIL_CHANGE_MAIL_PROXY, [(userdn, AT.MAIL)], mailproxy) if not self.hasMailObjectClass(uid): self.addMailObjectClass(uid) self.changeUserAttributes(uid, self.conf.attrs['mailproxy'], mailproxy, False) r.commit()
def changeMaildrop(self, uid, maildroplist): """ Change the user mail drop. @param uid: user name @type uid: str @param maildroplist: a list of all mail drop @type maildroplist: list """ userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.MAIL_CHANGE_MAIL_DROP, [(userdn, AT.MAIL)], maildroplist) if not self.hasMailObjectClass(uid): self.addMailObjectClass(uid) self.changeUserAttributes(uid, self.conf.attrs['maildrop'], maildroplist, False) r.commit()
def addMailGroup(self, group, mail): r = AF().log(PLUGIN_NAME, AA.MAIL_ADD_MAIL_GROUP, [(group, AT.MAIL_GROUP)], mail) group = group.encode("utf-8") cn = 'cn=' + group + ', ' + self.baseGroupsDN attrs = [] attrib = self.l.search_s(cn, ldap.SCOPE_BASE) c, attrs = attrib[0] newattrs = copy.deepcopy(attrs) if not 'mailGroup' in newattrs["objectClass"]: newattrs["objectClass"].append('mailGroup') if self.hasZarafaSupport() and not 'zarafa-group' in newattrs["objectClass"]: newattrs["objectClass"].append('zarafa-group') newattrs['mail'] = mail mlist = ldap.modlist.modifyModlist(attrs, newattrs) self.l.modify_s(cn, mlist) r.commit()
def addVDomain(self, domain): """ Add a virtual mail domain name entry in directory @param domain: virtual mail domain name @type domain: str """ r = AF().log(PLUGIN_NAME, AA.MAIL_ADD_VDOMAIN, [(domain, AT.VMDOMAIN)]) dn = "virtualdomain=" + domain + ", " + self.conf.vDomainDN entry = { "virtualdomain" : domain, "objectClass" : ("mailDomain", "top") } modlist = ldap.modlist.addModlist(entry) self.l.add_s(dn, modlist) r.commit()
def changeQuota(self, uid, mailuserquota): """ Change the user quota attribute. @param uid: user name @type uid: str @param mailuserquota: Quota in kB for uid @type mailuserquota: str """ userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.MAIL_CHANGE_MAIL_QUOTA, [(userdn, AT.MAIL)], mailuserquota) if not self.hasMailObjectClass(uid): self.addMailObjectClass(uid) self.changeUserAttributes(uid, self.conf.attrs['mailuserquota'], mailuserquota, False) r.commit()
def addRecordCNAME(self, zone, alias, cname, dnsClass="IN"): """ Add a canonical name record. The host name to which the alias is pointing must be a A record. CNAME chaining is not supported. @param zone: the DNS zone where the record is stored @type zone: str @param alias: alias pointing to the canonical name @type alias: str @param cname: CNAME to record (must be a registered A record) @type cname: str """ r = AF().log(PLUGIN_NAME, AA.NETWORK_ADD_RECORD_CNAME, [(zone, AT.ZONE), (alias, AT.RECORD_CNAME)], cname) # Check that the given cname is a A record record = self.getResourceRecord(zone, cname) try: if not "aRecord" in record[0][1]: raise "%s in not a A record" % cname except IndexError: raise "'%s' A record does not exist in the DNS zone" % cname if self.pdns: dn = "dc=" + alias + "," + "dc=" + zone + "," + self.configDns.dnsDN entry = { "associateddomain": alias + "." + zone, "objectClass": ["top", "domainrelatedobject", "dnsdomain2"], "dc": alias, "cnamerecord": cname + "." + zone, } else: # Add the CNAME record dn = "relativeDomainName=" + alias + "," + "ou=" + zone + "," + "ou=" + zone + "," + self.configDns.dnsDN entry = { "relativeDomainName": alias, "objectClass": ["top", "dNSZone"], "zoneName": zone, "dNSClass": dnsClass, "CNAMERecord": cname, } attributes = [(k, v) for k, v in entry.items()] self.l.add_s(dn, attributes) self.updateZoneSerial(zone) r.commit()
def setPPolicyAttribute(self, nameattribute, value): """ Set the value of the given LDAP attribute. Del the attribute if value is None @param nameattribute: LDAP attribute name @type nameattribute: str @param value: LDAP attribute value @type value: str """ if value is not None: r = AF().log(PLUGIN_NAME, AA.PPOLICY_MOD_USER_ATTR, [(self.dn, AT.USER), (nameattribute, AT.ATTRIBUTE)], value) if type(value) == bool: value = str(value).upper() elif type(value) == int: value = str(value) mode = ldap.MOD_REPLACE logger.debug('Setting %s to %s' % (nameattribute, value)) else: r = AF().log(PLUGIN_NAME, AA.PPOLICY_DEL_USER_ATTR, [(self.dn, AT.USER), (nameattribute, AT.ATTRIBUTE)], value) mode = ldap.MOD_DELETE logger.debug('Removing %s' % nameattribute) try: self.l.modify_s(self.dn, [(mode, nameattribute, value)]) except ldap.UNDEFINED_TYPE: logger.error("Attribute %s isn't defined on LDAP" % nameattribute) except ldap.INVALID_SYNTAX: logger.error("Invalid Syntax from the attribute value of %s on ldap" % nameattribute) r.commit() # if password reset request, we set sambaPwdLastSet to time()-24hours if nameattribute == 'pwdReset' and value == 'TRUE': userpolicy = self.getPPolicy() if not userpolicy: userpolicy = 'default' pwd_minage = PPolicy().listPPolicy(userpolicy)[0][1]['pwdMinAge'][0] try: from mmc.plugins import samba if samba.isSmbUser(self.userUid): samba.changeSambaAttributes(self.userUid, {'sambaPwdLastSet': str(int(time.time()) - int(pwd_minage))}) else: logger.debug('sambaPwdLastSet failed to set \ beause %s is not a samba user (pwdReset workaround)' % self.userUid) except ImportError: pass
def changeMailbox(self, uid, mailbox): """ Change the user mailbox attribute (mail delivery directory). @param uid: user name @type uid: str @param mailbox: a list of all mail aliases @type mailbox: mailbox value """ userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.MAIL_CHANGE_MAIL_BOX, [(userdn, AT.MAIL)], mailbox) if not self.hasMailObjectClass(uid): self.addMailObjectClass(uid) if mailbox: self.changeUserAttributes(uid, self.conf.attrs['mailbox'], mailbox, False) r.commit()
def setSOANSRecord(self, zoneName, nameserver): """ Set the name server for the SOA record. It updates the SOARecord field and nsRecord field of the @ LDAP entry of this given zone. """ r = AF().log(PLUGIN_NAME, AA.NETWORK_SET_SOA, [(zoneName, AT.ZONE)], nameserver) soaDN, soaData = self.getZoneSOA(zoneName) self.l.modify_s(soaDN, [(ldap.MOD_REPLACE, "nSRecord", [nameserver])]) # Also sync SOA record if there is one soaRecord = self.getSOARecord(zoneName) if soaRecord: soaRecord["nameserver"] = nameserver self.setSOARecord(zoneName, soaRecord) self.updateZoneSerial(zoneName) r.commit()
def changeMailhidden(self, uid, mailhidden): """ Change the user mailhidden attribute. @param uid: user name @type uid: str @param mailhidden: if the mail should be hidden or not @type mailhidden: bool """ if mailhidden: mailhidden = "YES" else: mailhidden = "NO" userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.MAIL_CHANGE_MAIL_HIDDEN, [(userdn, AT.MAIL)], mailhidden) if not self.hasMailObjectClass(uid): self.addMailObjectClass(uid) self.changeUserAttributes(uid, self.conf.attrs['mailhidden'], mailhidden, False) r.commit()
def restartSquid(self): """ Compile the blacklist database and reload squid. """ r = AF().log(PLUGIN_NAME, AA.PROXY_RESTART_SQUID) mmctools.shlaunch(self.config.sgBinary + ' -C ' + self.config.sgBlacklist) mmctools.shlaunch("chown " + self.config.squidGroup + "." + self.config.squidUser + " " + self.config.sgBlacklist + "*") psout = os.popen(self.config.squidReload, 'r') read = psout.read() if psout.close(): read = "error reloading squid" r.commit() return read
def deleteMailGroupAliases(self, group): """ Remove the alias of this group from all user entries """ r = AF().log(PLUGIN_NAME, AA.MAIL_DEL_MAIL_GRP_ALIAS, [(group, AT.MAIL_GROUP)], group) if hasMailGroupObjectClass(group): mailgroup = self.getDetailedGroup(group)["mail"][0] users = self.search( "(&(uid=*)(%s=%s))" % (self.conf.attrs['mailalias'], mailgroup), self.baseUsersDN, ["uid", self.conf.attrs['mailalias']]) for user in users: uid = user[0][1]["uid"][0] mailaliases = user[0][1][self.conf.attrs['mailalias']] mailaliases.remove(mailgroup) self.changeMailalias(uid, mailaliases) r.commit()
def removePPolicy(self): """ Remove the pwdPolicy objectClass from the current user, and the pwdPolicySubentry attribute. """ r = AF().log(PLUGIN_NAME, AA.PPOLICY_DEL_USER_PPOLICY, [(self.dn, AT.USER)]) # Remove pwdPolicy object class self.removeUserObjectClass(self.userUid, 'pwdPolicy') # Remove pwdPolicySubentry attribute from current user entry s = self.l.search_s(self.dn, ldap.SCOPE_BASE, attrlist = ['+', '*']) c, old = s[0] new = copy.deepcopy(old) if 'pwdPolicySubentry' in new: del new['pwdPolicySubentry'] # Update LDAP modlist = ldap.modlist.modifyModlist(old, new) self.l.modify_s(self.dn, modlist) r.commit() return True
def setVDomainDescription(self, domain, description): """ Set the virtualdomaindescription of a virtual mail domain name @param domain: virtual mail domain name @type domain: str @param description: description @type description: unicode """ r = AF().log(PLUGIN_NAME, AA.MAIL_SET_DOMAIN_DESC, [(domain, AT.VMDOMAIN)], description) dn = "virtualdomain=" + domain + ", " + self.conf.vDomainDN description = description.encode("utf-8") if description: self.l.modify_s(dn, [(ldap.MOD_REPLACE, "virtualdomaindescription", description)]) else: self.l.modify_s(dn, [(ldap.MOD_REPLACE, "virtualdomaindescription", "null")]) self.l.modify_s(dn, [(ldap.MOD_DELETE, "virtualdomaindescription", "null")]) r.commit()
def modifyZarafa(self, uid, attribute, value): events = { 'zarafaAdmin' : AA.MAIL_MOD_ZARAFA_ADMIN, 'zarafaSharedStoreOnly' : AA.MAIL_MOD_ZARAFA_SHAREDSTOREONLY, 'zarafaAccount' : AA.MAIL_MOD_ZARAFA_ACCOUNT, 'zarafaSendAsPrivilege' : AA.MAIL_MOD_ZARAFA_SENDASPRIVILEGE, 'zarafaHidden' : AA.MAIL_MOD_ZARAFA_HIDDEN } if attribute not in events: raise ValueError('Attribute %s is not managed' % attribute) userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, events[attribute], [(userdn, AT.MAIL)], value) if not self.hasMailObjectClass(uid): self.addMailObjectClass(uid) if not value: # If value is False or empty, we set the value to None so that it # is removed value = None elif value == True: value = '1' self.changeUserAttributes(uid, attribute, value, False) r.commit()
def delShare(self, name, remove): """ Delete a share from SAMBA configuration, and maybe delete the share directory from disk. The save method must be called to update smb.conf. @param name: Name of the share @param remove: If true, we physically remove the directory """ r = AF().log(PLUGIN_NAME, AA.SAMBA_DEL_SHARE, [(name, AT.SHARE)], remove) path = self.getContent(name, 'path') if not path: raise Exception('Share "' + name + '" does not exist') del self.config[name] if remove: if os.path.exists(path): shutil.rmtree(path) else: logger.error('The "%s" share path does not exist.' % path) r.commit()
def lockUser(self, uid): """ Lock the SAMBA user """ userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.SAMBA_LOCK_USER, [(userdn, AT.USER)]) s = self.l.search_s(userdn, ldap.SCOPE_BASE) c, old = s[0] new = old.copy() flags = new["sambaAcctFlags"][0] # flags should be something like "[U ]" if not "L" in flags: flags = flags.strip("[]") flags = flags.strip() flags = flags + "L" flags = "[" + flags.ljust(11) + "]" new["sambaAcctFlags"] = [flags] modlist = ldap.modlist.modifyModlist(old, new) self.l.modify_s(userdn, modlist) r.commit() return 0
def addPPolicy(self, ppolicyName): """ Add the pwdPolicy and pwdPolicySubentry objectClass to the current user, and set the pwdPolicySubentry attribute to the select ppolicy DN """ if not self.hasPPolicy(): r = AF().log(PLUGIN_NAME, AA.PPOLICY_ADD_USER_PPOLICY, [(self.dn, AT.USER)]) # Get current user entry s = self.l.search_s(self.dn, ldap.SCOPE_BASE, attrlist = ['+', '*']) c, old = s[0] new = copy.deepcopy(old) if not "pwdPolicy" in new["objectClass"]: new["objectClass"].append("pwdPolicy") new["pwdAttribute"] = "userPassword" new['pwdPolicySubentry'] = PPolicy().getPPolicy(ppolicyName)[0] # Update LDAP modlist = ldap.modlist.modifyModlist(old, new) self.l.modify_s(self.dn, modlist) r.commit() return True return False
def setVDomainQuota(self, domain, quota): """ Set the quota of a virtual mail domain name @param domain: virtual mail domain name @type domain: str @param quota: created user quota in the virtual domain @type description: unicode """ r = AF().log(PLUGIN_NAME, AA.MAIL_SET_DOMAIN_QUOTA, [(domain, AT.VMDOMAIN)], quota) dn = "virtualdomain=" + domain + ", " + self.conf.vDomainDN try: int(quota) except ValueError: quota = None if quota: self.l.modify_s(dn, [(ldap.MOD_REPLACE, self.conf.attrs['mailuserquota'], quota)]) else: self.l.modify_s(dn, [(ldap.MOD_DELETE, self.conf.attrs['mailuserquota'], None)]) r.commit()
def addMailObjectClass(self, uid, maildrop=None): r = AF().log(PLUGIN_NAME, AA.MAIL_ADD_MAIL_CLASS, [(uid, AT.MAIL)]) # Get current user entry dn = 'uid=' + uid + ',' + self.baseUsersDN s = self.l.search_s(dn, ldap.SCOPE_BASE) c, old = s[0] new = self._applyUserDefault(old, self.conf.userDefault) if not "mailAccount" in new["objectClass"]: new["objectClass"].append("mailAccount") if self.hasZarafaSupport(): rz = AF().log(PLUGIN_NAME, AA.MAIL_ADD_ZARAFA_CLASS, [(uid, AT.MAIL)]) if not 'zarafa-user' in new['objectClass']: new['objectClass'].append('zarafa-user') # Add maildrop attribute to user if we are not in virtual domain mode if maildrop == None and not self.hasVDomainSupport(): maildrop = uid new[self.conf.attrs['maildrop']] = maildrop if self.hasVDomainSupport(): # If the user has her/his mail address in a VDomain, set quota according to domain policy maildomain = new["mail"][0].split("@")[1] try: vdomain = self.getVDomain(maildomain) new[self.conf.attrs['mailuserquota']] = vdomain[0][1][ self.conf.attrs['mailuserquota']] except ldap.NO_SUCH_OBJECT: pass except KeyError: pass # Update LDAP modlist = ldap.modlist.modifyModlist(old, new) self.l.modify_s(dn, modlist) r.commit() if self.hasZarafaSupport(): rz.commit()
def setHostAliases(self, zone, host, aliases): """ Set all aliases of a host. The host must be a A record. A CNAME record will be created for each alias @param zone: DNS zone to modify @type zone: str @param host: host to which aliases are added @type host: str @param aliases: host aliases to set @type aliases: list @return: the alias that could not be set, because a resource record with this name already exist @rtype: list """ r = AF().log(PLUGIN_NAME, AA.NETWORK_SET_HOST_ALIASES, [(zone, AT.ZONE), (host, AT.RECORD_A)], aliases) ret = [] oldaliases = [] for record in self.getCNAMEs(zone, host): oldalias = record[1][self.relativeDomainNameField][0] oldaliases.append(oldalias) if oldalias not in aliases: # Delete alias self.l.delete_s(record[0]) for alias in aliases: if alias not in oldaliases: # Add alias try: self.addRecordCNAME(zone, alias, host) except ldap.ALREADY_EXISTS: ret.append(alias) r.commit() return ret
def backupShare(share, media, login): """ Launch as a background process the backup of a share """ r = AF().log(PLUGIN_NAME, AA.SAMBA_BACKUP_SHARE, [(share, AT.SHARE), (login, AT.USER)], media) config = BasePluginConfig("base") cmd = os.path.join(config.backuptools, "backup.sh") if share == "homes": # FIXME: Maybe we should have a configuration directive to tell that # all users home are stored into /home savedir = "/home/" else: smbObj = SambaConf(SambaConfig("samba").samba_conf_file) savedir = smbObj.getContent(share, "path") # Run backup process in background shlaunchBackground( cmd + " " + share + " " + savedir + " " + config.backupdir + " " + login + " " + media + " " + config.backuptools, "backup share " + share, progressBackup) r.commit() return os.path.join(config.backupdir, "%s-%s-%s" % (login, share, strftime("%Y%m%d")))
def updatePPolicy(self, ppolicyName): """ Update the pwdPolicySubentry attribute of the current user """ if self.hasPPolicy(): if not ppolicyName: return self.removePPolicy() else: # get the ppolicy dn ppolicyDN = PPolicy().getPPolicy(ppolicyName)[0] r = AF().log(PLUGIN_NAME, AA.PPOLICY_MOD_USER_PPOLICY, [(self.dn, AT.USER)]) try: self.l.modify_s(self.dn, [(ldap.MOD_REPLACE, 'pwdPolicySubentry', ppolicyDN)]) except ldap.UNDEFINED_TYPE: logging.getLogger().error("Attribute %s isn't defined on ldap" % 'pwdPolicySubentry') except ldap.INVALID_SYNTAX: logging.getLogger().error("Invalid Syntax from the attribute value of %s on ldap" % 'pwdPolicySubentry') r.commit() return True else: return self.addPPolicy(ppolicyName) return False
def changeMailEnable(self, uid, enabled): """ Set the user mailenable attribute. This tells if the user receive mail or not. @param uid: user name @type uid: str @param enabled: Boolean to specify if mail is enabled or not @type enabled: bool """ if enabled: action = AA.MAIL_ENABLE attr_val = "OK" else: action = AA.MAIL_DISABLE attr_val = "NONE" r = AF().log(PLUGIN_NAME, action, [(uid, AT.MAIL)], enabled) if not self.hasMailObjectClass(uid): self.addMailObjectClass(uid) self.changeUserAttributes(uid, self.conf.attrs['mailenable'], attr_val, False) r.commit()
def setAttribute(self, nameattribute, value, ppolicyName=None): """ Set value to the given attribute. @param nameattribute: LDAP attribute name @type nameattribute: str @param value: LDAP attribute value @type value: str """ if not ppolicyName: ppolicyDN = self.configPPolicy.ppolicydefaultdn else: ppolicyDN = "cn=" + ppolicyName + "," + self.configPPolicy.ppolicydn r = AF().log(PLUGIN_NAME, AA.PPOLICY_MOD_ATTR, [(ppolicyDN, AT.PPOLICY), (nameattribute, AT.ATTRIBUTE)], value) if value is not None: if type(value) == bool: value = str(value).upper() elif type(value) == int: value = str(value) try: self.l.modify_s(ppolicyDN, [(ldap.MOD_REPLACE, nameattribute, value)]) ppolicy_attr_changed.send(sender=self, ppolicy_name=ppolicyName, ppolicy_attr=nameattribute, ppolicy_attr_value=value) except ldap.UNDEFINED_TYPE: logger.error("Attribute %s isn't defined on ldap" % nameattribute) except ldap.INVALID_SYNTAX: logger.error( "Invalid Syntax from the attribute value of %s on ldap" % nameattribute) r.commit()
def changeUserPrimaryGroup(self, uid, group): """ Change the SAMBA primary group of a user, if the sambaPrimaryGroupSID of this user is defined. Else do nothing. @param uid: login of the user @type uid: unicode @param group: new primary group @type uid: unicode """ userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.SAMBA_CHANGE_USER_PRIMARY_GRP, [(userdn,AT.USER),(group, AT.GROUP)]) try: self.getDetailedUser(uid)["sambaPrimaryGroupSID"] except KeyError: # This user has no sambaPrimaryGroupSID set # So nothing to do return gidNumber = self.getDetailedGroup(group)["gidNumber"][0] sid = self.gid2sid(gidNumber) if sid: self.changeUserAttributes(uid, "sambaPrimaryGroupSID", sid) r.commit()
def enableUser(self, uid): """ Enable the SAMBA user """ userdn = self.searchUserDN(uid) r = AF().log(PLUGIN_NAME, AA.SAMBA_ENABLE_USER, [(userdn, AT.USER)]) s = self.l.search_s(userdn, ldap.SCOPE_BASE) c, old = s[0] new = old.copy() flags = new["sambaAcctFlags"][0] flags = flags.strip("[]") flags = flags.strip() if not flags.startswith("D"): # Huh ? User has been already enabled # Do nothing pass else: flags = flags[1:] flags = "[" + flags.ljust(11) + "]" new["sambaAcctFlags"] = [flags] modlist = ldap.modlist.modifyModlist(old, new) self.l.modify_s(userdn, modlist) r.commit() return 0
def addZone(self, name, network=None, netmask=None, reverse=False, description=None, nameserver="ns", nameserverip=None): """ @param name: the zone name @param network: the network address defined in this zone (needed to build the reverse zone) @param netmask: the netmask address (needed to build the reverse zone) """ r = AF().log(PLUGIN_NAME, AA.NETWORK_ADD_DNS_ZONE, [(name, AT.ZONE)], network) if reverse: if network == None or netmask == None: raise "Won't create reverse zone as asked, missing network or netmask" netmask = int(netmask) # Build network address start according to netmask elements = network.split(".") if netmask == 8: network = elements[0] elif netmask == 16: network = ".".join(elements[0:2]) elif netmask == 24: network = ".".join(elements[0:3]) else: raise "Won't create reverse zone as asked, netmask is not 8, 16 or 24" if not self.pdns: # Create Bind configuration files f = open(os.path.join(self.configDns.bindLdapDir, name), "w") d = { "zone": name, "ldapurl": self.config.ldapurl + "/" + self.configDns.dnsDN, "dnsreader": urllib.quote(self.configDns.dnsReader), "dnsreaderpasswd": urllib.quote(self.configDns.dnsReaderPassword) } f.write(self.templateZone % d) if reverse: d["zone"] = self.reverseZone(network) f.write(self.templateZone % d) f.close() os.chmod(os.path.join(self.configDns.bindLdapDir, name), 0640) f = open(self.configDns.bindLdap, "r") found = False toadd = 'include "' + os.path.join( self.configDns.bindLdapChrootConfPath, name) + '";\n' for line in f: if line == toadd: found = True break f.close() if not found: f = open(self.configDns.bindLdap, "a") f.write(toadd) f.close() # Create the needed zones object in LDAP if reverse: reverseZone = self.reverseZone(network) self.addDnsZone(reverseZone, "Reverse zone for " + name, name) else: reverseZone = None self.addDnsZone(name, description) # Fill SOA self.addSOA(name) if self.pdns: ns = nameserver + "." + name mailaddr = "admin." + name else: ns = nameserver + "." + name + "." mailaddr = "admin." + name + "." rec = { "nameserver": ns, "emailaddr": mailaddr, "serial": self.computeSerial(), "refresh": "2D", "retry": "15M", "expiry": "2W", "minimum": "1H", } self.setSOARecord(name, rec) self.setSOANSRecord(name, ns) # A record defaults to the server ip self.setSOAARecord(name, nameserverip) # Fill SOA for reverse zone too if reverse: self.addSOA(reverseZone, name) self.setSOARecord(reverseZone, rec) self.setSOANSRecord(reverseZone, ns) if nameserverip: # Add a A record for the primary nameserver self.addRecordA(name, nameserver, nameserverip) r.commit()
def addRecordA(self, zone, hostname, ip, container=None, dnsClass="IN"): """ Add an entry for a zone and its reverse zone. @return: 0 if the host has been added in a reverse zone too, 1 if not @rtype: int """ r = AF().log(PLUGIN_NAME, AA.NETWORK_ADD_RECORD_A, [(zone, AT.ZONE), (hostname, AT.RECORD_A)], ip) ret = 1 if self.pdns: dn = "dc=" + hostname + "," + "dc=" + zone + "," + self.configDns.dnsDN entry = { "associateddomain": hostname + "." + zone, "objectClass": ["top", "domainrelatedobject", "dnsdomain2"], "dc": hostname, "aRecord": ip, } else: if not container: container = zone dn = "relativeDomainName=" + hostname + "," + "ou=" + zone + "," + "ou=" + container + "," + self.configDns.dnsDN entry = { "relativeDomainName": hostname, "objectClass": ["top", "dNSZone"], "zoneName": zone, "dNSClass": dnsClass, "aRecord": ip, } attributes = [(k, v) for k, v in entry.items()] self.l.add_s(dn, attributes) self.updateZoneSerial(zone) revZone = self.getReverseZone(zone) # Add host to corresponding reverse zone if there is one if revZone: # For now, we only manage a single reverse zone revZone = revZone[0] ipStart = self.translateReverse(revZone) # Check that the given IP can fit into the reverse zone if ip.startswith(ipStart): # Ok, add it ipLast = ip.replace(ipStart, "", 1) elements = ipLast.split(".") elements.reverse() elements.pop() # Remove the last "." relative = ".".join(elements) if self.pdns: dn = "dc=" + relative + "," + "dc=" + revZone + "," + self.configDns.dnsDN entry = { "dc": relative, "objectClass": ["top", "domainrelatedobject", "dnsdomain2"], "associatedDomain": relative + "." + revZone, "pTRRecord": hostname + "." + zone, } else: dn = "relativeDomainName=" + relative + "," + "ou=" + revZone + "," + "ou=" + container + "," + self.configDns.dnsDN entry = { "relativeDomainName": relative, "objectClass": ["top", "dNSZone"], "zoneName": revZone, "dNSClass": dnsClass, "pTRRecord": hostname + "." + zone + ".", } attributes = [(k, v) for k, v in entry.items()] self.l.add_s(dn, attributes) self.updateZoneSerial(revZone) ret = 0 r.commit() return ret