コード例 #1
0
ファイル: rc.py プロジェクト: nezirus/djmd
	def set(self, option, value, section=None):
		'''Set the given option to the specified value

		Keyword arguments:
		section -- Section name override
		'''
		s = section if section else self.default_section
		try:
			self.parser.set(s, option, value)
		except configparser.NoSectionError as e:
			error('Configuration problem: %s' % (e))
コード例 #2
0
ファイル: rc.py プロジェクト: nezirus/djmd
	def items(self, section=None):
		'''Return a list of (name, value) pairs for each option
		in the given section.

		Keyword arguments:
		section -- Section name override
		'''
		s = section if section else self.default_section
		try:
			return self.parser.items(s)
		except configparser.Error as e:
			error('Configuration problem: %s' % (e))
コード例 #3
0
ファイル: rc.py プロジェクト: nezirus/djmd
	def __init__(self, default_section='djmd'):
		'''
		Keyword arguments:
		default_section -- Section name for get() calls
		'''

		self.default_section = default_section
		cmd_parser = ArgumentParser(description=
			'Don\'t Judge Mail - Postfix Policy Daemon')

		# Options with no counterpart in conf file
		cmd_parser.add_argument('--conf', dest='conf_file')
		cmd_parser.add_argument('--version', action='store_true')

		# Overridable options
		# Defaults should be provided in configuration file, not here
		cmd_parser.add_argument('--allow-hosts', metavar='HOST1,HOST2')
		cmd_parser.add_argument('--debug', action='store_true')
		cmd_parser.add_argument('--listen', metavar='IP_ADDR:PORT')
		cmd_parser.add_argument('--pid-file', metavar='/PATH/TO/daemon_name.pid')
		cmd_parser.add_argument('--plugins', metavar='PLUGIN1,PLUGIN2')
		cmd_parser.add_argument('--servers', metavar='N')
		cmd_parser.add_argument('--init-database', action='store_true')

		self.cmdline = vars(cmd_parser.parse_args())

		if 'version' in self.cmdline and self.cmdline['version']:
			from djm.__version__ import version
			print('djmd v%s'%(version))
			sys.exit(0)

		try:
			self.parser = configparser.SafeConfigParser()

			if 'conf_file' not in self.cmdline:
				# OK, no conf file. Add default section where the cmdline args
				# shall be saved (btw, one can't add section named 'default')
				self.parser.add_section(default_section)
			else:
				cf = open(self.cmdline['conf_file'])
				self.parser.readfp(cf)
				cf.close()

			for k, v in self.cmdline.items():
				if v:
					self.parser.set('djmd', k, str(v))
		except configparser.Error as e:
			error('Configuration problem: %s' % (e), sys.stderr)
		except EnvironmentError:
			error('Could not open configuration file: %s' %
				(self.cmdline['conf_file']), sys.stderr)
コード例 #4
0
ファイル: database.py プロジェクト: nezirus/djmd
	def __call__(self, conf, db='default'):
		if not self.is_green:
			make_green()
			self.is_green = True

		db_params = {}
		for k, v in conf.items('database:%s' % db):
			db_params[k] = v

		try:
			con = psycopg2.connect(**db_params)
			return con
		except psycopg2.Error as e:
			error('Could not connect to the %s database.' % (db,))
コード例 #5
0
ファイル: rc.py プロジェクト: nezirus/djmd
	def get(self, option, section=None, default=None, mandatory=True):
		'''Get an option value for the named section

		Keyword arguments:
		section -- Section name override
		mandatory -- Enforce existance of option value
		default -- Default value for non mandatory options
		'''

		s = section if section else self.default_section
		try:
			return self.parser.get(s, option)
		except configparser.NoOptionError as e:
			if not mandatory:
				return default
			else:
				error('Configuration problem: %s' % (e))
		except configparser.Error as e:
			error('Configuration problem: %s' % (e))
コード例 #6
0
ファイル: quota.py プロジェクト: nezirus/djmd
	def __call__(self, request):
		conf = self.conf

		db_name = conf.get('database', 'plugin:quota', 'default', mandatory=False)
		db = connect(conf, db_name)

		if not db:
			return PolicyResponse().dunno()

		try:
			quota_keys = {
				'sasl_username': request['sasl_username'],
				'sasl_sender': request['sasl_sender'],
				'sender': request['sender'],
				'sender_domain': None,
				'recipient': request['recipient'],
				'recipient_count': request['recipient_count'],
				'recipient_domain': request['recipient'].rsplit('@', 1)[1],
				'client_address': request['client_address'],
				'size': request['size'],
			}
		except (KeyError, IndexError):
			error('Missing policy request attribute')
			return PolicyResponse().dunno()

		if '@' in request['sasl_username']:
			quota_keys['sender_domain'] = request['sasl_username'].rsplit('@', 1)[1]
		elif '@' in request['sasl_sender']:
			quota_keys['sender_domain'] = request['sasl_sender'].rsplit('@', 1)[1]
		else:
			quota_keys['sender_domain'] = request['sender'].rsplit('@', 1)[1]

		hd = hosted_domains()
		sd = quota_keys['sender_domain']
		rd = quota_keys['recipient_domain']

		if conf.get('ignore_local', 'plugin:quota') == 'true' and \
			(sd == rd or ((sd in hd) and (rd in hd))):
			return PolicyResponse().dunno()

		c = cursor(db)
		action = None

		for item in self.targeted_policies(c, quota_keys):
			if item['tracking_id'] is None:
				self.new_quota_tracking_item(db, c, item, quota_keys)
		
			resp = self.quota_for(db, c, item, quota_keys)
			action = resp.action

			if action == 'reject':
				return resp
	
		# Stop processing if we've passed positive targeted policies
		if action:
			return resp

		# Maybe our user doesn't exist in quota table?
		for item in self.new_default_policies(c):
			self.new_quota_tracking_item(db, c, item, quota_keys)

		# Process default policies (if any)
		for item in self.default_policies(c, quota_keys):
			resp = self.quota_for(db, c, item, quota_keys)
			if resp.action == 'reject':
				return resp

		return PolicyResponse().dunno()
コード例 #7
0
ファイル: greylist.py プロジェクト: nezirus/djmd
	def __call__(self, request):
		conf = self.conf
		db_name = conf.get('database', 'plugin:greylist', 'default', mandatory=False)
		db = connect(conf, db_name)
		resp = PolicyResponse()

		if not db:
			return resp.dunno()

		try:
			gk = {
				'sender': request['sender'],
				'sender_domain': request['sender'].rsplit('@', 1)[1],
				'recipient': request['recipient'],
				'client_address': request['client_address'],
			}
		except (KeyError, IndexError):
			error('Missing policy request attribute')
			return resp.dunno()


		# Don't greylist SASL authenticated users
		if 'sasl_username' in request and '@' in request['sasl_username']:
			return resp.dunno()

		c = cursor(db)

		# Client whitelist
		c.execute('''SELECT id FROM greylist_sender_wl WHERE
			sender=%s OR sender=%s''',
			(gk['sender_domain'], gk['client_address']))

		if c.rowcount > 0:
			resp.prepend('X-Greylist', 'Whitelisted by djmd')
			return resp.accept()

		# Auto whitelisted (per domain)
		c.execute('''SELECT id FROM greylist_sender_awl WHERE
			sender_domain=%s AND sender_address=%s''',
			(gk['sender_domain'], gk['client_address']))

		if c.rowcount > 0:
			c.execute('''UPDATE greylist_sender_awl SET last_seen=NOW()
				WHERE sender_domain=%s AND sender_address=%s''',
				(gk['sender_domain'], gk['client_address']))
			db.commit()
			resp.prepend('X-Greylist', 'AWL by djmd')
			return resp.accept()
		
		# New connection or second connection (AWL candidate)
		try:
			c.execute('''INSERT INTO greylist_tracking(sender, sender_address,
				recipient) VALUES(%s, %s, %s)''', 
				(gk['sender'], gk['client_address'], gk['recipient']))
			db.commit()
		except IntegrityError as e:
			db.rollback()
			c.execute('''SELECT first_seen, (extract(epoch from (NOW() -
				first_seen)))::integer as elapsed_time FROM greylist_tracking
				WHERE sender=%s AND sender_address=%s AND recipient=%s''', 
				(gk['sender'], gk['client_address'], gk['recipient']))
			gt = c.fetchone()

			greylist_delay = int(conf.get('greylist_delay', 'plugin:greylist'))

			if gt[1] > greylist_delay:
				try:
					c.execute('''INSERT INTO greylist_sender_awl(sender_domain,
						sender_address, first_seen, last_seen)
						VALUES(%s, %s, %s, NOW())''',
					(gk['sender_domain'], gk['client_address'], gt[0]))
					db.commit()
				except IntegrityError as e:
					# Already whitelisted, move on
					db.rollback()

				# AWL
				resp.prepend('X-Greylist', 'AWL by djmd')
				return resp.accept()

		return resp.reject(msg=conf.get('msg', 'plugin:greylist'))