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 serialize(self): smbconf = SambaConf() data = { 'sessions': len(smbconf.getConnected()), 'shares': len(smbconf.getSmbStatus()) } return data
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 modShare( name, path, comment, usergroups, users, permAll, admingroups, browseable=True, av=0, customparameters=None ): smbObj = SambaConf(SambaConfig("samba").samba_conf_file) smbObj.addShare( name, path, comment, usergroups, users, permAll, admingroups, browseable, av, customparameters, True ) smbObj.save()
def updateDomainNextRID(self): """ Increment sambaNextRID """ conf = SambaConf() domain = conf.getContent("global", "workgroup") result = self.search("(&(objectClass=sambaDomain)(sambaDomainName=%s))" % domain) dn, old = result[0][0] # update the old attributes new = old.copy() new['sambaNextRid'] = [ str(int(old['sambaNextRid'][0]) + 1) ] modlist = ldap.modlist.modifyModlist(old, new) self.l.modify_s(dn, modlist)
def getDomain(self): """ Return the LDAP sambaDomainName entry corresponding to the domain specified in smb.conf @return: the sambaDomainName entry @rtype: dict """ conf = SambaConf() domain = conf.getContent("global", "workgroup") result = self.search("(&(objectClass=sambaDomain)(sambaDomainName=%s))" % domain) if len(result): ret = result[0][0][1] else: ret = {} 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 modShare(name, path, comment, perms, admingroups, recursive=True, browseable=True, av=0, customparameters=None): smbObj = SambaConf(SambaConfig("samba").samba_conf_file) smbObj.addShare(name, path, comment, perms, admingroups, recursive, browseable, av, customparameters, True) smbObj.save()
def getDetailedShares(filter="", start=0, end=None): """Get a complete array of information about all shares""" smbObj = SambaConf(SambaConfig("samba").samba_conf_file) resList = smbObj.getDetailedShares(filter, start, end) return resList
def getConnected(): return SambaConf().getConnected()
def isPdc(): try: smbObj = SambaConf(SambaConfig("samba").samba_conf_file) except: raise Exception("Can't open SAMBA configuration file") return smbObj.isPdc()
def getSmbInfo(): """get main information of global section""" smbObj = SambaConf(SambaConfig("samba").samba_conf_file) return smbObj.getSmbInfo()
def shareInfo(name): """get an array of information about a share""" smbObj = SambaConf(SambaConfig("samba").samba_conf_file) return smbObj.shareInfo(name)
def getAdminUsersOnShare(name): return SambaConf( SambaConfig("samba").samba_conf_file).getAdminUsersOnShare(name)
def serialize(self): smbconf = SambaConf() data = {'sessions': len(smbconf.getConnected()), 'shares': len(smbconf.getSmbStatus())} return data
def getACLOnShare(name): smbObj = SambaConf(SambaConfig("samba").samba_conf_file) return smbObj.getACLOnShare(name)
def getDetailedShares(): """Get a complete array of information about all shares""" smbObj = SambaConf(SambaConfig("samba").samba_conf_file) resList = smbObj.getDetailedShares() return resList
def addShare(name, path, comment, perms, admingroups, recursive=True, browseable=True, av=0, customparameters=None): smbObj = SambaConf(SambaConfig("samba").samba_conf_file) smbObj.addShare(name, path, comment, perms, admingroups, recursive, browseable, av, customparameters) smbObj.save()
def setDomainPolicy(self): """ Try to sync the samba domain policy with the default OpenLDAP policy """ conf = SambaConf() domain = conf.getContent("global", "workgroup") result = self.search("(&(objectClass=sambaDomain)(sambaDomainName=%s))" % domain) dn, old = result[0][0] # update the old attributes new = old.copy() # get the default ppolicy values try: from mmc.plugins.ppolicy import getDefaultPPolicy except ImportError: # don't try to change samba policies pass else: try: ppolicy = getDefaultPPolicy()[1] except (ldap.NO_SUCH_OBJECT, IOError): # no default password policy set pass else: # samba default values options = { "sambaMinPwdLength": ["5"], "sambaMaxPwdAge": ["-1"], "sambaMinPwdAge": ["0"], "sambaPwdHistoryLength": ["0"], "sambaLockoutThreshold": ["0"], "sambaLockoutDuration": ["30"] } if 'pwdMinLength' in ppolicy: options['sambaMinPwdLength'] = ppolicy['pwdMinLength'] if 'pwdMaxAge' in ppolicy and ppolicy['pwdMaxAge'][0] != "0": options['sambaMaxPwdAge'] = ppolicy['pwdMaxAge'] if 'pwdMinAge' in ppolicy: options['sambaMinPwdAge'] = ppolicy['pwdMinAge'] if 'pwdInHistory' in ppolicy: options['sambaPwdHistoryLength'] = ppolicy['pwdInHistory'] if 'pwdLockout' in ppolicy and ppolicy['pwdLockout'][0] == "TRUE" \ and 'pwdMaxFailure' in ppolicy and ppolicy['pwdMaxFailure'][0] != '0': if 'pwdLockoutDuration' in ppolicy: options['sambaLockoutDuration'] = ppolicy['pwdLockoutDuration'] options['sambaLockoutThreshold'] = ppolicy['pwdMaxFailure'] else: options['sambaLockoutThreshold'] = ["0"] update = False for attr, value in options.iteritems(): # Update attributes if needed if new[attr] != value: new[attr] = value update = True if update: modlist = ldap.modlist.modifyModlist(old, new) try: self.l.modify_s(dn, modlist) except ldap.UNDEFINED_TYPE: # don't fail if attributes don't exist pass logger.info("SAMBA domain policy synchronized with password policies")
def isAuthorizedSharePath(path): return SambaConf( SambaConfig("samba").samba_conf_file).isAuthorizedSharePath(path)
def delShare(name, file): smbObj = SambaConf(SambaConfig("samba").samba_conf_file) smbObj.delShare(name, file) smbObj.save() return 0
def isBrowseable(name): return SambaConf(SambaConfig("samba").samba_conf_file).isBrowseable(name)
def shareCustomParameters(name): """get an array of additionnal params about a share""" smbObj = SambaConf(SambaConfig("samba").samba_conf_file) return smbObj.shareCustomParameters(name)
def smbInfoSave(options): """save information about global section""" smbObj = SambaConf(SambaConfig("samba").samba_conf_file) return smbObj.smbInfoSave(options)
def isProfiles(): """ check if global profiles are setup """ smbObj = SambaConf(SambaConfig("samba").samba_conf_file) return smbObj.isProfiles()
def getSmbStatus(): return SambaConf().getSmbStatus()
def activate(): """ this function define if the module "base" can be activated. @return: return True if this module can be activate @rtype: boolean """ config = SambaConfig("samba") if config.disabled: logger.info("samba plugin disabled by configuration.") return False if config.defaultSharesPath: if config.defaultSharesPath.endswith("/"): logger.error("Trailing / is not allowed in defaultSharesPath") return False if not os.path.exists(config.defaultSharesPath): logger.error("The default shares path '%s' does not exist" % config.defaultSharesPath) return False for cpath in config.authorizedSharePaths: if cpath.endswith("/"): logger.error("Trailing / is not allowed in authorizedSharePaths") return False if not os.path.exists(cpath): logger.error("The authorized share path '%s' does not exist" % cpath) return False # Verify if samba conf file exist conf = config.samba_conf_file if not os.path.exists(conf): logger.error(conf + " does not exist") return False # validate smb.conf smbconf = SambaConf() if not smbconf.validate(conf): logger.error("SAMBA configuration file is not valid") return False # For each share, test if it sharePath exists for share in getDetailedShares(): shareName = share[0] infos = shareInfo(shareName) if infos: sharePath = infos["sharePath"] if sharePath and not "%" in sharePath and not os.path.exists(sharePath): # only show error logger.error("The samba share path '%s' does not exist." % sharePath) else: return False try: ldapObj = ldapUserGroupControl() except ldap.INVALID_CREDENTIALS: logger.error("Can't bind to LDAP: invalid credentials.") return False # Test if the Samba LDAP schema is available in the directory try: schema = ldapObj.getSchema("sambaSamAccount") if len(schema) <= 0: logger.error("Samba schema is not included in LDAP directory") return False except: logger.exception("invalid schema") return False # Verify if init script exist init = config.samba_init_script if not os.path.exists(init): logger.error(init + " does not exist") return False # If SAMBA is defined as a PDC, make extra checks if smbconf.isPdc(): samba = SambaLDAP() # Create SAMBA computers account OU if it doesn't exist head, path = samba.baseComputersDN.split(",", 1) ouName = head.split("=")[1] samba.addOu(ouName, path) # Check that a sambaDomainName entry is in LDAP directory domainInfos = samba.getDomain() # Set domain policy samba.setDomainPolicy() if not domainInfos: logger.error( "Can't find sambaDomainName entry in LDAP for domain %s. Please check your SAMBA LDAP configuration." % smbconf.getContent("global", "workgroup") ) return False smbconfbasesuffix = smbconf.getContent("global", "ldap suffix") if not smbconfbasesuffix: logger.error("SAMBA 'ldap suffix' option is not setted.") return False if ldap.explode_dn(samba.baseDN) != ldap.explode_dn(smbconfbasesuffix): logger.error("SAMBA 'ldap suffix' option is not equal to MMC 'baseDN' option.") return False # Check that SAMBA and MMC given OU are in sync for option in [ ("ldap user suffix", "baseUsersDN", samba.baseUsersDN), ("ldap group suffix", "baseGroupsDN", samba.baseGroupsDN), ("ldap machine suffix", "baseComputersDN", samba.baseComputersDN), ]: smbconfsuffix = smbconf.getContent("global", option[0]) if not smbconfsuffix: logger.error("SAMBA '" + option[0] + "' option is not setted") return False # Do a case insensitive comparison of the corresponding MMC / SAMBA options if ldap.explode_rdn(smbconfsuffix)[0].lower() != ldap.explode_rdn(option[2])[0].lower(): logger.error("SAMBA option '" + option[0] + "' is not equal to MMC '" + option[1] + "' option.") return False # Check that "ldap delete dn" SAMBA option is set to "No" smbconfdeletedn = smbconf.isValueTrue(smbconf.getContent("global", "ldap delete dn")) if smbconfdeletedn == 1: logger.error("SAMBA option 'ldap delete dn' must be disabled.") return False # Check that Domain Computers group exists # We need it to put a machine account in the right group when joigning it to the domain if not samba.getDomainComputersGroup(): logger.error( "Can't find sambaGroupMapping entry in LDAP corresponding to 'Domain Computers' group. Please check your SAMBA LDAP configuration." ) return False # Check that Domain Admins group exists if not samba.getDomainAdminsGroup(): logger.error( "Can't find sambaGroupMapping entry in LDAP corresponding to 'Domain Admins' group. Please check your SAMBA LDAP configuration." ) return False # Check that Domain Guests group exists if not samba.getDomainGuestsGroup(): logger.error( "Can't find sambaGroupMapping entry in LDAP corresponding to 'Domain Guests' group. Please check your SAMBA LDAP configuration." ) return False # Check that Domain Users group exists if not samba.getDomainUsersGroup(): logger.error( "Can't find sambaGroupMapping entry in LDAP corresponding to 'Domain Users' group. Please check your SAMBA LDAP configuration." ) return False # Check that add machine script option is set, and that the given script exist addMachineScript = smbconf.getContent("global", "add machine script") if not addMachineScript: logger.error("SAMBA 'add machine script' option is not set.") return False else: script = addMachineScript.split(" ")[0] if not os.path.exists(script): logger.error("SAMBA 'add machine script' option is set to a non existing file: " + script) return False # Issue a warning if NSCD is running if ( os.path.exists("/var/run/nscd.pid") or os.path.exists("/var/run/.nscd_socket") or os.path.exists("/var/run/nscd") ): logger.warning("Looks like NSCD is installed on your system. You should not run NSCD on a SAMBA server.") # Check that os level is set to 255 oslevel = smbconf.getContent("global", "os level") if int(oslevel) < 255: logger.debug("Set SAMBA os level to 255.") smbconf.setContent("global", "os level", "255") smbconf.save() reloadSamba() try: from mmc.plugins.dashboard.manager import DashboardManager from mmc.plugins.samba.panel import SambaPanel DM = DashboardManager() DM.register_panel(SambaPanel("samba")) except ImportError: pass return True
def activate(): """ this function define if the module "base" can be activated. @return: return True if this module can be activate @rtype: boolean """ config = SambaConfig("samba") if config.disabled: logger.info("samba plugin disabled by configuration.") return False if config.defaultSharesPath: if config.defaultSharesPath.endswith("/"): logger.error("Trailing / is not allowed in defaultSharesPath") return False if not os.path.exists(config.defaultSharesPath): logger.error("The default shares path '%s' does not exist" % config.defaultSharesPath) return False for cpath in config.authorizedSharePaths: if cpath.endswith("/"): logger.error("Trailing / is not allowed in authorizedSharePaths") return False if not os.path.exists(cpath): logger.error("The authorized share path '%s' does not exist" % cpath) return False # Verify if samba conf file exist conf = config.samba_conf_file if not os.path.exists(conf): logger.error(conf + " does not exist") return False # validate smb.conf smbconf = SambaConf() if not smbconf.validate(conf): logger.error("SAMBA configuration file is not valid") return False # For each share, test if it sharePath exists for share in getDetailedShares(): shareName = share[0] infos = shareInfo(shareName) if infos: sharePath = infos['sharePath'] if sharePath and not '%' in sharePath and not os.path.exists( sharePath): # only show error logger.error("The samba share path '%s' does not exist." % sharePath) else: return False try: ldapObj = ldapUserGroupControl() except ldap.INVALID_CREDENTIALS: logger.error("Can't bind to LDAP: invalid credentials.") return False # Test if the Samba LDAP schema is available in the directory try: schema = ldapObj.getSchema("sambaSamAccount") if len(schema) <= 0: logger.error("Samba schema is not included in LDAP directory") return False except: logger.exception("invalid schema") return False # Verify if init script exist init = config.samba_init_script if not os.path.exists(init): logger.error(init + " does not exist") return False # If SAMBA is defined as a PDC, make extra checks if smbconf.isPdc(): samba = SambaLDAP() # Create SAMBA computers account OU if it doesn't exist head, path = samba.baseComputersDN.split(",", 1) ouName = head.split("=")[1] samba.addOu(ouName, path) # Check that a sambaDomainName entry is in LDAP directory domainInfos = samba.getDomain() # Set domain policy samba.setDomainPolicy() if not domainInfos: logger.error( "Can't find sambaDomainName entry in LDAP for domain %s. Please check your SAMBA LDAP configuration." % smbconf.getContent("global", "workgroup")) return False smbconfbasesuffix = smbconf.getContent("global", "ldap suffix") if not smbconfbasesuffix: logger.error("SAMBA 'ldap suffix' option is not setted.") return False if ldap.explode_dn(samba.baseDN) != ldap.explode_dn(smbconfbasesuffix): logger.error( "SAMBA 'ldap suffix' option is not equal to MMC 'baseDN' option." ) return False # Check that SAMBA and MMC given OU are in sync for option in [ ("ldap user suffix", "baseUsersDN", samba.baseUsersDN), ("ldap group suffix", "baseGroupsDN", samba.baseGroupsDN), ("ldap machine suffix", "baseComputersDN", samba.baseComputersDN) ]: smbconfsuffix = smbconf.getContent("global", option[0]) if not smbconfsuffix: logger.error("SAMBA '" + option[0] + "' option is not setted") return False # Do a case insensitive comparison of the corresponding MMC / SAMBA options if ldap.explode_rdn(smbconfsuffix)[0].lower() != ldap.explode_rdn( option[2])[0].lower(): logger.error("SAMBA option '" + option[0] + "' is not equal to MMC '" + option[1] + "' option.") return False # Check that "ldap delete dn" SAMBA option is set to "No" smbconfdeletedn = smbconf.isValueTrue( smbconf.getContent("global", "ldap delete dn")) if smbconfdeletedn == 1: logger.error("SAMBA option 'ldap delete dn' must be disabled.") return False # Check that Domain Computers group exists # We need it to put a machine account in the right group when joigning it to the domain if not samba.getDomainComputersGroup(): logger.error( "Can't find sambaGroupMapping entry in LDAP corresponding to 'Domain Computers' group. Please check your SAMBA LDAP configuration." ) return False # Check that Domain Admins group exists if not samba.getDomainAdminsGroup(): logger.error( "Can't find sambaGroupMapping entry in LDAP corresponding to 'Domain Admins' group. Please check your SAMBA LDAP configuration." ) return False # Check that Domain Guests group exists if not samba.getDomainGuestsGroup(): logger.error( "Can't find sambaGroupMapping entry in LDAP corresponding to 'Domain Guests' group. Please check your SAMBA LDAP configuration." ) return False # Check that Domain Users group exists if not samba.getDomainUsersGroup(): logger.error( "Can't find sambaGroupMapping entry in LDAP corresponding to 'Domain Users' group. Please check your SAMBA LDAP configuration." ) return False # Check that add machine script option is set, and that the given script exist addMachineScript = smbconf.getContent("global", "add machine script") if not addMachineScript: logger.error("SAMBA 'add machine script' option is not set.") return False else: script = addMachineScript.split(" ")[0] if not os.path.exists(script): logger.error( "SAMBA 'add machine script' option is set to a non existing file: " + script) return False # Issue a warning if NSCD is running if os.path.exists("/var/run/nscd.pid") or os.path.exists( "/var/run/.nscd_socket") or os.path.exists("/var/run/nscd"): logger.warning( "Looks like NSCD is installed on your system. You should not run NSCD on a SAMBA server." ) # Check that os level is set to 255 oslevel = smbconf.getContent("global", "os level") if int(oslevel) < 255: logger.debug("Set SAMBA os level to 255.") smbconf.setContent("global", "os level", "255") smbconf.save() reloadSamba() try: from mmc.plugins.dashboard.manager import DashboardManager from mmc.plugins.samba.panel import SambaPanel DM = DashboardManager() DM.register_panel(SambaPanel("samba")) except ImportError: pass return True