Example #1
0
	def delete(self):
		log = logging.getLogger('flscp')
		conf = FLSConfig.getInstance()

		# delete!
		# 1. remove credentials
		# 2. remove entry from /etc/postfix/fls/aliases
		# 3. remove entry from /etc/postfix/fls/mailboxes
		# 4. remove entry from /etc/postfix/fls/sender-access
		# 5. remove entry from mail_users
		# 7. remove complete mails in /var/mail/,... directory
		# 6. postmap all relevant entries
		self.updateCredentials()
		self.updateMailboxes()
		self.updateAliases()
		self.updateSenderAccess()

		if self.exists():
			db = MailDatabase.getInstance()
			cx = db.getCursor()
			query = ('SELECT mail_id, mail_addr FROM mail_users WHERE mail_id = %s')
			cx.execute(query, (self.id,))
			for (mail_id, mail_addr,) in cx:
				(mail, domain) = mail_addr.split('@')
				path = '%s/%s/%s/' % (conf.get('mailserver', 'basemailpath'), domain, mail) 
				if os.path.exists(path):
					try:
						os.removedirs(path)
					except Exception as e:
						log.warning('Error when removing directory: %s' % (e,))

			query = ('DELETE FROM mail_users WHERE mail_id = %s')
			cx.execute(query, (self.id,))
			cx.close()
Example #2
0
	def getDomains(self):
		data = []
		db = MailDatabase.getInstance()
		cursor = db.getCursor()
		query = (
			'SELECT domain_id, domain_parent, domain_name, ipv6, ipv4, domain_gid, domain_uid, domain_created, \
			domain_last_modified, domain_srvpath, domain_status FROM domain'
		)
		cursor.execute(query)
		for (domain_id, domain_parent, domain_name, ipv6, ipv4, gid, uid, created, modified, srvpath, state) in cursor:
			data.append(
				{
					'id': domain_id, 
					'name': domain_name,
					'ipv6': ipv6,
					'ipv4': ipv4,
					'gid': gid,
					'uid': uid,
					'srvpath': srvpath,
					'parent': domain_parent,
					'created': created,
					'modified': modified,
					'state': state
				}
			)

		cursor.close()
		
		return data
Example #3
0
	def getDns(self, domain = None):
		data = []
		db = MailDatabase.getInstance()
		cursor = db.getCursor()
		if domain is None:
			query = (
				'SELECT dns_id, domain_id FROM dns'
			)
			cursor.execute(query)
		else:
			query = (
				'SELECT dns_id, domain_id FROM dns WHERE domain_id = %s'
			)
			cursor.execute(query, (domain,))

		dnsIds = []
		for (dns_id, domain_id) in cursor:
			dnsIds.append(dns_id)

		for i in dnsIds:
			dns = Dns(i)
			dns.load()
			data.append(dns.toDict())
			del(dns)

		cursor.close()
		
		return data
Example #4
0
	def create(self):
		# 1. create entry in domain
		# 2. insert the things in domain file of postfix
		# 3. hash the domain file
		# 4. create default dns entries?
		# 5. generate a bind file
		# 6. reload bind
		if self.exists():
			raise KeyError('Domain "%s" already exists!' % (self.name,))

		# is it a valid domain?
		if len(self.name) <= 0:
			raise ValueError('No valid domain given!')

		self.created = time.time()
		self.modified = time.time()
		db = MailDatabase.getInstance()
		cx = db.getCursor()
		self.state = Domain.STATE_CREATE
		query = (
			'INSERT INTO domain (domain_parent, domain_name, ipv6, ipv4, domain_gid, domain_uid, domain_created, \
			domain_last_modified, domain_srvpath, domain_status) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)'
		)
		cx.execute(
			query, 
			(
				self.parent, self.name, self.ipv6, self.ipv4, self.gid, self.uid, 
				self.created, self.modified, self.srvpath, self.state
			)
		)
		db.commit()
Example #5
0
	def setState(self, state):
		db = MailDatabase.getInstance()
		cx = db.getCursor()
		query = ('UPDATE mail_users SET status = %s WHERE mail_id = %s')
		cx.execute(query, (state, self.id))
		db.commit()
		cx.close()

		self.state = state
Example #6
0
	def exists(self):
		# check if entry exists already in mail_users!
		db = MailDatabase.getInstance()
		cx = db.getCursor()
		query = ('SELECT mail_id FROM mail_users WHERE mail_addr = %s')
		cx.execute(query, ('%s@%s' % (self.mail, self.domain),))
		exists = len(cx.fetchall()) > 0
		cx.close()
		return exists
Example #7
0
	def exists(self):
		exists = False
		db = MailDatabase.getInstance()
		cx = db.getCursor()
		query = ('SELECT domain_id FROM domain WHERE domain_name = %s and domain_parent = %s')
		cx.execute(query, (self.name, self.parent))
		exists = len(cx.fetchall()) > 0
		cx.close()
		return exists
Example #8
0
	def getByEMail(self, mail):
		log = logging.getLogger('flscp')
		ma = MailAccount()
		db = MailDatabase.getInstance()
		cx = db.getCursor()
		query = ('SELECT mail_id, mail_acc, mail_pass, mail_forward, domain_id, mail_type, sub_id, status, quota, mail_addr, alternative_addr, authcode, authvalid, enabled FROM mail_users WHERE mail_addr = %s')
		cx.execute(query, (mail.lower(),))
		if cx is None:
			log.warning('Execution failed in MailAccount::getByEMail(%s).' % (mail,))
			return None

		try:
			resultRow = cx.fetchone()
		except:
			log.critical('Got error in MailAccount::getByEMail: %s' % (e,))
			try:
				cx.close()
			except:
				pass
			return None
		else:
			if resultRow is None:
				log.info('No user found by mail %s' % (mail,))
				return None

		try:
			(mail_id, mail_acc, mail_pass, mail_forward, domain_id, mail_type, sub_id, status, quota, mail_addr, alternative_addr, authcode, authvalid, enabled) = resultRow
			ma.id = mail_id
			ma.quota = quota
			ma.mail = mail_acc
			ma.hashPw = mail_pass
			ma.domain = mail_addr.split('@')[1]
			ma.altMail = alternative_addr
			ma.forward = mail_forward.split(',')
			ma.type = MailAccount.TYPE_ACCOUNT
			if mail_type == 'fwdsmtp':
				ma.type = MailAccount.TYPE_FWDSMTP
			elif mail_type == 'forward':
				ma.type = MailAccount.TYPE_FORWARD
			ma.status = status
			ma.authCode = authcode
			ma.authValid = authvalid
			ma.enabled = bool(enabled)
		except Exception as e:
			log.critical('Got error in MailAccount::getByEMail: %s' % (e,))
			cx.close()
			return None
		else:
			cx.close()
			self = ma
			return self
Example #9
0
	def changePassword(self, pwd):
		self.pw = pwd
		self.hashPassword()
		db = MailDatabase.getInstance()
		try:
			cx = db.getCursor()
			query = (
				'UPDATE mail_users SET mail_pass = %s, authcode = NULL, authvalid = NULL WHERE mail_id = %s'
			)
			cx.execute(query, (self.hashPw, self.id))
			db.commit()
			cx.close()
		except:
			return False
		else:
			self.updateCredentials()
			return True
Example #10
0
	def createAuthCode(self):
		self.authCode = hashlib.md5(str(hash(random.SystemRandom().uniform(0, 1000))).encode('utf-8')).hexdigest()
		self.authValid = datetime.datetime.now() + datetime.timedelta(hours=2)

		db = MailDatabase.getInstance()
		try:
			cx = db.getCursor()
			query = (
				'UPDATE mail_users SET authcode = %s, authvalid = %s WHERE mail_id = %s'
			)
			cx.execute(query, (self.authCode, self.authValid.strftime('%Y-%m-%d %H:%M:%S'), self.id))
			db.commit()
			cx.close()
		except:
			return False
		else:
			return True
Example #11
0
	def update(self, oldDomain = None):
		# is it a valid domain?
		if len(self.name) <= 0:
			raise ValueError('No valid domain given!')

		self.modified = time.time()
		db = MailDatabase.getInstance()
		cx = db.getCursor()
		self.state = Domain.STATE_OK
		query = (
			'UPDATE domain SET ipv6 = %s, ipv4 = %s, domain_gid = %s, domain_uid = %s, domain_last_modified = %s, \
			domain_srvpath = %s, domain_status = %s WHERE domain_id = %s'
		)
		cx.execute(
			query, 
			(
				self.ipv6, self.ipv4, self.gid, self.uid, 
				self.modified, self.srvpath, self.state, self.id
			)
		)
		db.commit()

		# if we have updated, we now have to move the data folder?
		if oldDomain.srvpath != self.srvpath and len(oldDomain) > 0 and len(self.srvpath) > 0:
			parentFolder = self.srvpath
			if parentFolder == '/':
				parentFolder = parentFolder[:-1]
			parentFolderSplit = parentFolder.split('/')
			parentFolder = '/'.join(parentFolderSplit[:-1])
			if not os.path.exists(parentFolder):
				os.makedirs(parentFolder)

			os.rename(oldDomain.srvpath, self.srvpath)
		elif len(self.srvpath) > 0:
			if not os.path.exists(self.srvpath):
				os.makedirs(self.srvpath)
				os.chmod(self.srvpath, 0o750)
				os.chown(self.srvpath, self.uid, self.gid)

				# now create the default structure
				os.makedirs(os.path.join(self.srvpath, 'htdocs'))
				os.chmod(os.path.join(self.srvpath, 'htdocs'), 0o750)
				os.chown(os.path.join(self.srvpath, 'htdocs'), self.uid, self.gid)
Example #12
0
	def getByName(dom, name):
		log = logging.getLogger('flscp')
		db = MailDatabase.getInstance()
		cx = db.getCursor()
		query = ('SELECT domain_id, domain_name FROM domain WHERE domain_name = %s')
		try:
			cx.execute(query, (name,))
			(domain_id, domain_name) = cx.fetchone()
			dom = Domain()
			dom.id = domain_id
			dom.name = domain_name
		except Exception as e:
			dom = None
			log.warning('Could not find domain.')
			raise KeyError('Domain "%s" could not be found!' % (name,))
		finally:
			cx.close()

		self = dom
		return self
Example #13
0
	def getMails(self):
		db = MailDatabase.getInstance()
		domainsRaw = self.getDomains()
		domains = {}
		for f in domainsRaw:
			domains[f['id']] = f['name']

		data = []
		cursor = db.getCursor()
		query = (
			'SELECT m.mail_id, m.mail_acc, m.mail_addr, m.mail_type, m.mail_forward, m.quota, m.status, m.domain_id, m.alternative_addr, \
			m.enabled, q.bytes FROM mail_users m LEFT JOIN quota_dovecot q ON m.mail_addr = q.username'
		)
		cursor.execute(query)
		for (mail_id, mail_acc, mail_addr, mail_type, mail_forward, quota, status, domain_id, alternative_addr, enabled, usedBytes) in cursor:
			quotaSts = 0.00
			if usedBytes is not None:
				if usedBytes > 0 and quota > 0:
					quotaSts = round(usedBytes*100/quota, 2)

			data.append(
				{
					'id': mail_id, 
					'mail': mail_acc,
					'altMail': alternative_addr if alternative_addr is not None else '',
					'forward': mail_forward.split(',') if mail_forward != '_no_' else [],
					'domain': domains[domain_id],
					'domainId': domain_id,
					'state': status,
					'type': mail_type,
					'pw': '',
					'genPw': False,
					'enabled': bool(enabled),
					'quota': quota,
					'quotaSts': quotaSts
				}
			)

		cursor.close()
		
		return data
Example #14
0
	def load(self):
		log = logging.getLogger('flscp')
		if self.id is None:
			log.info('Can not load data for a domain with no id!')
			return False

		state = False

		db = MailDatabase.getInstance()
		cx = db.getCursor()
		query = (
			'SELECT domain_id, domain_parent, domain_name, ipv6, ipv4, domain_gid, domain_uid, domain_srvpath, \
			domain_created, domain_last_modified, domain_status FROM domain WHERE domain_id = %s LIMIT 1'
		)
		try:
			cx.execute(query, (self.id,))
			for (did, parent, domain_name, ipv6, ipv4, gid, uid, srvpath, created, modified, state) in cx:
				self.id = did
				self.parent = parent
				self.name = domain_name
				self.ipv6 = ipv6
				self.ipv4 = ipv4
				self.gid = gid
				self.uid = uid
				self.srvpath = srvpath
				self.created = created
				self.modified = modified
				self.state = state
		except Exception as e:
			log.warning('Could not load the domain %s because of %s' % (self.id, str(e)))
			state = False
		else:
			state = True
		finally:
			cx.close()

		return state
Example #15
0
	def create(self):
		log = logging.getLogger('flscp')
		# create:
		# 1. update mail_users
		# 2. update credentials, if given
		# 3. update /etc/postfix/fls/mailboxes
		# 4. update aliases
		# 5. update sender-access (we could later be implement to restrict sending!)
		# postmap all relevant entries
		if self.exists():
			# already exists! 
			raise KeyError('Mail "%s@%s" already exists!' % (self.mail, self.domain))
		
		# get domain id! (if not exist: create!)
		try:
			d = Domain.getByName(self.domain)
		except KeyError:
			raise

		# pw entered?
		if len(self.pw.strip()) > 0:
			self.hashPassword()

		db = MailDatabase.getInstance()
		cx = db.getCursor()
		query = (
			'INSERT INTO mail_users (mail_acc, mail_pass, mail_forward, domain_id, mail_type, status, quota, mail_addr, alternative_addr, enabled) ' \
			'VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)'
		)
		cx.execute(
			query, 
			(
				self.mail, self.hashPw, ','.join(self.forward), d.id, self.type, self.state, self.quota, 
				'%s@%s' % (self.mail, self.domain), self.altMail, str(int(self.enabled))
			)
		)
		db.commit()
		log.debug('executed mysql statement: %s' % (cx.statement,))
		id = cx.lastrowid
		if id is None:
			cx.close()
			return False
		else:
			self.id = id

		# update credentials...
		self.updateCredentials()

		# now update mailboxes files!
		if not self.updateMailboxes():
			cx.close()
			return False

		# update aliases
		if not self.updateAliases():
			# remove entry from updateMailboxes?
			cx.close()
			return False

		# update sender-access
		if not self.updateSenderAccess():
			# remove entry from updateMailboxes and Aliases ?
			cx.close()
			return False

		cx.close()
		
		# all best? Than go forward and update set state,...
		self.setState(MailAccount.STATE_OK)

		# notify 
		if len(self.altMail) > 0:
			m = Mailer(self)
			state = False
			if self.type == MailAccount.TYPE_ACCOUNT \
					or self.type == MailAccount.TYPE_FWDSMTP:
				state = m.newAccount()
			else:
				state = m.newForward()

			if state:
				log.info('User is notified about account change!')
			else:
				log.warning('Unknown error while notifying user!')
		else:
			log.info('User is not notified because we have no address of him!')

		# reset info
		self.pw = ''
		self.hashPw = ''
		self.genPw = False
Example #16
0
	def save(self):
		log = logging.getLogger('flscp')
		conf = FLSConfig.getInstance()

		if self.state == MailAccount.STATE_CREATE:
			self.create()
			return
		elif self.state == MailAccount.STATE_DELETE:
			self.delete()
			return
		elif self.state == MailAccount.STATE_QUOTA:
			self.recalculateQuota()
			return

		# now save!
		# -> see create - but if key changed (mail address!) remove
		# all entries before and rename folder in /var/mail,... directory
		# get original data!
		if not self.exists():
			self.create()

		# get domain id! (if not exist: create!)
		try:
			d = Domain.getByName(self.domain)
		except KeyError:
			raise

		# pw entered?
		if len(self.pw.strip()) > 0:
			log.info('Hash password for user %s' % (self.mail,))
			self.hashPassword()

		db = MailDatabase.getInstance()
		cx = db.getCursor()
		query = ('SELECT mail_id, mail_addr, mail_type FROM mail_users WHERE mail_id = %s')
		cx.execute(query, (self.id,))
		(mail_id, mail_addr, mail_type) = cx.fetchone()
		(mail, domain) = mail_addr.split('@')
		cx.close()

		cx = db.getCursor()
		if (self.type == MailAccount.TYPE_ACCOUNT and self.hashPw != '') \
			or (self.type == MailAccount.TYPE_FWDSMTP and self.hashPw != '') \
			or self.type == MailAccount.TYPE_FORWARD:
			query = (
				'UPDATE mail_users SET mail_acc = %s, mail_pass = %s, mail_forward = %s, ' \
				'domain_id = %s, mail_type = %s, status = %s, quota = %s, mail_addr = %s, ' \
				'alternative_addr = %s, enabled = %s WHERE mail_id = %s'
			)
			params = (
				self.mail, self.hashPw, ','.join(self.forward), d.id, self.type, self.state, self.quota, 
				'%s@%s' % (self.mail, self.domain), self.altMail, str(int(self.enabled)), self.id
			)
		else:
			query = (
				'UPDATE mail_users SET mail_acc = %s, mail_forward = %s, ' \
				'domain_id = %s, mail_type = %s, status = %s, quota = %s, mail_addr = %s, ' \
				'alternative_addr = %s, enabled = %s WHERE mail_id = %s'
			)
			params = (
				self.mail, ','.join(self.forward), d.id, self.type, self.state, self.quota, 
				'%s@%s' % (self.mail, self.domain), self.altMail, str(int(self.enabled)), self.id
			)

		cx.execute(
			query, 
			params
		)
		db.commit()
		log.debug('executed mysql statement: %s' % (cx.statement,))

		# update credentials...
		# if pw was entered or type changed
		if mail_type != self.type or self.pw.strip() != '':
			self.updateCredentials()

		# now update mailboxes files!
		if not self.updateMailboxes(oldMail=mail, oldDomain=domain):
			cx.close()
			return False

		# update aliases
		if not self.updateAliases(oldMail=mail, oldDomain=domain):
			# remove entry from updateMailboxes?
			cx.close()
			return False

		# update sender-access
		if not self.updateSenderAccess(oldMail=mail, oldDomain=domain):
			# remove entry from updateMailboxes and Aliases ?
			cx.close()
			return False

		# rename folders - but only if target directory does not exist
		# (we had to throw fatal error if target directory exists!)
		oldPath = '%s/%s/%s/' % (conf.get('mailserver', 'basemailpath'), domain, mail)
		path = '%s/%s/%s/' % (conf.get('mailserver', 'basemailpath'), self.domain, self.mail)
		if os.path.exists(oldPath):
			if os.path.exists(path):
				log.error('Could not move "%s" to "%s", because it already exists!' % (path,))
			else:
				try:
					os.rename(oldPath, path)
				except OSError as e:
					log.warning('Got OSError - Does directory exists? (%s)' % (e,))
				except Exception as e:
					log.warning('Got unexpected exception (%s)!' % (e,))

		cx.close()

		# all best? Than go forward and update set state,...
		self.setState(MailAccount.STATE_OK)

		# notify
		if len(self.altMail) > 0:
			m = Mailer(self)
			state = False
			if self.type == MailAccount.TYPE_ACCOUNT \
					or self.type == MailAccount.TYPE_FWDSMTP:
				state = m.changeAccount()
			else:
				state = m.changeForward()

			if state:
				log.info('User is notified about account change!')
			else:
				log.warning('Unknown error while notifying user!')
		else:
			log.info('User is not notified because we have no address of him!')

		# reset info
		self.pw = ''
		self.hashPw = ''
		self.genPw = False