# Author: Zhang Huangbin import sys import os import time import web from socket import getfqdn from urllib import urlencode from controllers import base from libs import __url_iredadmin_ldap_latest__, __version__, __no__, __id__ from libs import iredutils, languages from libs.ldaplib import auth, admin as adminlib, ldaputils, connUtils, attrs from libs.amavisd import quarantine, log as amavisdlog cfg = web.iredconfig session = web.config.get('_session') class Login: def GET(self): if session.get('logged') is True: return web.seeother('/dashboard') else: i = web.input(_unicode=False) # Show login page. return web.render('login.html', languagemaps=languages.getLanguageMaps(), webmaster=session.get('webmaster'), msg=i.get('msg'), ) def POST(self): # Get username, password. i = web.input(_unicode=False) # Get LDAP server related settings from web form. #server = web.safestr(i.get('server')) #basedn = web.safestr(i.get('basedn')) #admindn = web.safestr(i.get('admindn')) #vmailadmindn = web.safestr(i.get('vmailadmindn')) #vmailadminpw = web.safestr(i.get('vmailadminpw')) # TODO in login page # - Check 'Secure connection via STARTTLS' # - SLAPD port # Set/change variables in web.iredconfig if necessary. #cfg.ldap['uri'] = 'ldap://' + web.safestr(i.get('server')) + ':389' #cfg.ldap['basedn'] = basedn #cfg.ldap['domainadmin_dn'] = admindn #cfg.ldap['bind_dn'] = vmailadmindn #cfg.ldap['bind_pw'] = vmailadminpw # import them after changing web.iredconfig. #from libs.ldaplib import auth, admin, ldaputils, connUtils username = web.safestr(i.get('username', '').strip()) password = i.get('password', '').strip() save_pass = web.safestr(i.get('save_pass', 'no').strip()) if not iredutils.isEmail(username): return web.seeother('/login?msg=INVALID_USERNAME') if len(password) == 0: return web.seeother('/login?msg=EMPTY_PASSWORD') # Convert username to ldap dn. userdn = ldaputils.convKeywordToDN(username, accountType='admin') # Return True if auth success, otherwise return error msg. self.auth_result = auth.Auth(cfg.ldap.get('uri', 'ldap://127.0.0.1/'), userdn, password,) if self.auth_result == True: session['username'] = username session['logged'] = True # Read preferred language from db. adminLib = adminlib.Admin() #session['lang'] = adminLib.getPreferredLanguage(userdn) or cfg.general.get('lang', 'en_US') adminProfile = adminLib.profile(username) if adminProfile[0] is True: cn = adminProfile[1][0][1].get('cn', [None])[0] lang = adminProfile[1][0][1].get('preferredLanguage', [cfg.general.get('lang', 'en_US')])[0] session['cn'] = cn session['lang'] = lang else: pass web.config.session_parameters['cookie_name'] = 'iRedAdmin' # Session expire when client ip was changed. web.config.session_parameters['ignore_change_ip'] = False # Don't ignore session expiration. web.config.session_parameters['ignore_expiry'] = False if save_pass == 'yes': # Session timeout (in seconds). web.config.session_parameters['timeout'] = 86400 # 24 hours else: # Expire session when browser closed. web.config.session_parameters['timeout'] = 600 # 10 minutes web.logger(msg="Login success", event='login',) return web.seeother('/dashboard/checknew') else: session['failedTimes'] += 1 web.logger(msg="Login failed.", admin=username, event='login', loglevel='error',) return web.seeother('/login?msg=%s' % self.auth_result) class Logout: @base.require_login def GET(self): session.kill() return web.seeother('/login') class Dashboard: @base.require_login def GET(self, checknew=''): i = web.input(_unicode=False,) if len(checknew) > 0: self.checknew = True else: self.checknew = False # Get network interface related infomation. netif_data = {} try: import netifaces ifaces = netifaces.interfaces() for iface in ifaces: addr = netifaces.ifaddresses(iface) if netifaces.AF_INET in addr.keys(): data = addr[netifaces.AF_INET][0] try: netif_data[iface] = {'addr': data['addr'], 'netmask': data['netmask'], } except: pass except: pass # Check new version. if session.get('domainGlobalAdmin') is True and self.checknew is True: try: curdate = time.strftime('%Y-%m-%d') vars = dict(date=curdate) r = web.admindb.select('updatelog', vars=vars, where='date >= $date',) if len(r) == 0: urlInfo = { 'a': cfg.general.get('webmaster', session.username), 'v': __version__, 'o': __no__, 'f': __id__, 'host': getfqdn(), } url = __url_iredadmin_ldap_latest__ + '?' + urlencode(urlInfo) newVersionInfo = iredutils.getNewVersion(url) # Always remove all old records, just keep the last one. web.admindb.delete('updatelog', vars=vars, where='date < $date',) # Insert updating date. web.admindb.insert('updatelog', date=curdate,) else: newVersionInfo = (None, ) except Exception, e: newVersionInfo = (False, str(e)) else: newVersionInfo = (None, ) # Get numbers of existing messages and quota bytes. # Set None as default, so that it's easy to detect them in Jinja2 template. totalMessages = None totalBytes = None if session.get('enableShowUsedQuota') is True: try: resultOfSum = web.admindb.query('''\ SELECT SUM(messages) AS totalMessages, \ SUM(bytes) AS totalBytes \ FROM used_quota \ ''') counterOfSum = resultOfSum[0] totalMessages = counterOfSum.totalMessages totalBytes = counterOfSum.totalBytes except Exception, e: pass # Get records of quarantined mails. amavisdQuarantineCount = 0 amavisdQuarantineRecords = [] if session.get('enableAmavisdQuarantine') is True: quarantineLib = quarantine.Quarantine() # Show only 10 records in Dashboard. (amavisdQuarantineCount, amavisdQuarantineRecords) = quarantineLib.getRecordsOfQuarantinedMails(sizelimit=10,) # Get number of incoming/outgoing emails in latest 24 hours. numberOfIncomingMails = 0 numberOfOutgoingMails = 0 numberOfVirusMails = 0 topSenders = [] topRecipients = [] if session.get('enableAmavisdLoggingIntoSQL') is True: allReversedDomainNames = [] amavisdLogLib = amavisdlog.Log() # Get all managed domain names and reversed names. if cfg.general.get('backend') == 'ldap': allDomains = [] adminLib = adminlib.Admin() result_all_domains = adminLib.getManagedDomains(session.get('username'), attrs=['domainName'],) if result_all_domains[0] is True: for i in result_all_domains[1]: domain = i[1].get('domainName', [''])[0] allDomains += [domain] allReversedDomainNames = amavisdLogLib.reverseDomainNames(allDomains) numberOfIncomingMails = amavisdLogLib.getNumberOfIncomingMails(allReversedDomainNames, 86400) numberOfOutgoingMails = amavisdLogLib.getNumberOfOutgoingMails(allReversedDomainNames, 86400) numberOfVirusMails = amavisdLogLib.getNumberOfVirusMails(allReversedDomainNames, 86400) topSenders = amavisdLogLib.getTopUser( reversedDomainNames=allReversedDomainNames, logType='sent', timeLength=86400, number=10, ) topRecipients = amavisdLogLib.getTopUser( reversedDomainNames=allReversedDomainNames, logType='received', timeLength=86400, number=10, ) return web.render( 'ldap/dashboard.html', version=__version__, hostname=getfqdn(), uptime=iredutils.getServerUptime(), loadavg=os.getloadavg(), netif_data=netif_data, newVersionInfo=newVersionInfo, amavisdQuarantineCount=amavisdQuarantineCount, amavisdQuarantineRecords=amavisdQuarantineRecords, totalMessages=totalMessages, totalBytes=totalBytes, numberOfIncomingMails=numberOfIncomingMails, numberOfOutgoingMails=numberOfOutgoingMails, numberOfVirusMails=numberOfVirusMails, topSenders=topSenders, topRecipients=topRecipients, ) class ExportLdif: @base.require_global_admin def GET(self, accountType, value): #from libs.ldaplib import connUtils, ldaputils connutils = connUtils.Utils() result = connutils.exportLdif(accountType=accountType, value=value) if result[0] is True: web.header('Content-Type', 'text/html') return result[1].replace('\n', '
') else: return ldaputils.getExceptionDesc(result[1]) class Search: @base.require_login def GET(self): i = web.input() return web.render( 'ldap/search.html', msg=i.get('msg'), ) @base.require_login def POST(self): #from libs.ldaplib import connUtils i = web.input() s = i.get('searchString') if s is None or len(s) == 0: results = (False, []) else: connutils = connUtils.Utils() results = connutils.search(web.safestr(s)) # Group account types. users = [] maillists = [] aliases = [] if results[0] is True: for account in results[1]: if 'mailUser' in account[1].get('objectClass', []): users += [account[1]] elif 'mailList' in account[1].get('objectClass', []): maillists += [account[1]] elif 'mailAlias' in account[1].get('objectClass', []): aliases += [account[1]] else: pass return web.render( 'ldap/search.html', totalResults=len(results[1]), users=users, maillists=maillists, aliases=aliases, msg=i.get('msg'), ) class OperationsFromSearchPage: @base.require_login def GET(self, *args, **kw): return web.seeother('/search') @base.require_login def POST(self, accountType): #from libs.ldaplib import connUtils, ldaputils, attrs self.accountType = web.safestr(accountType) i = web.input(_unicode=False, domainName=[], mail=[]) # Get action. self.action = i.get('action', None) # Result collector. result = {} if self.accountType in attrs.ACCOUNT_TYPES_EMAIL: self.accounts = [web.safestr(v).lower() for v in i.get('mail', []) if iredutils.isEmail(web.safestr(v)) ] connutils = connUtils.Utils() for account in self.accounts: self.domain = account.split('@')[-1] if self.action in ['enable', 'disable',]: try: connutils.enableOrDisableAccount( domain=self.domain, account=account, dn=ldaputils.convKeywordToDN(account, accountType=self.accountType), action=self.action, ) except Exception,e: result[account] = ldaputils.getExceptionDesc(e) if self.action in ['delete',]: try: connutils.deleteObjWithDN( domain=self.domain, dn=ldaputils.convKeywordToDN(account, accountType=self.accountType), account=account, accountType='user', ) except Exception, e: result[account] = ldaputils.getExceptionDesc(e) if len(result) == 0: return web.seeother('/search?msg=SUCCESS') else: return web.seeother('/search?msg=%s' % str(result))