Sunday, February 28, 2010

Automatic archiving of IMAP mailbox

I was looking for a way to let my IMAP server automatically move old mail to the correct IMAP folder based on a given specification. I wanted to simply drag mail that I wanted archived to a IMAP folder called Archives, and then let the server put it in the correct subfolder itself. Inspired by http://wiki.dovecot.org/HowTo/RefilterMail , I wrote this Python script:

#!/usr/bin/python
import imaplib, re, os

server = imaplib.IMAP4('localhost')
server.login('username', 'password')
r = server.select('Archives')
resp, items = server.search(None, 'ALL')

for m in items[0].split():
resp, data = server.fetch(m, '(BODY[HEADER.FIELDS (SUBJECT FROM TO)])')
_, headers = data[0]

dst = None
if re.search('To: .*@student.dtu.dk', headers): dst = 'Archives.2010.DTU'
if re.search('Subject: .*\[somelist\]', headers): dst = 'Archives.2010.Somelist'
if dst == None: dst = 'Archives.2010'

resp, data = server.copy(m, dst)
if resp == 'OK':
server.store(m, '+Flags', '\\Deleted')

server.expunge()
You can obscure the password by using base64.b64decode to prevent people seeing you password when looking over your shoulder.

To make the script run automatically every time a mail is dropped to the Archives folder, use incron. Type incrontab -e and write the following line
/home/username/Maildir/.Archives/cur/ IN_MOVED_TO,IN_ONESHOT python /path/to/script
Where /path/to/script here is the path of the above Python script.

Also, if you want to use this automatic triggering, add the following line to the end of the Python script
os.system('incrontab --reload')

Friday, January 22, 2010

Rogue DHCP detector in Nagios

This Python script I created can be used with Nagios to warn if there are unauthorized DHCP servers on the network. No third party libraries are used.

At the moment the script only checks at IP level, and does not return the MAC address of the rogue server. My plan is to expand this at some stage, but at the moment we do not really need this in our setup.


#!/usr/bin/python
from socket import *
from binascii import *
from random import *
from struct import *

# local machine mac address
chaddr = unhexlify('001122334455')

# allowed dhcp servers
whitelist = set(['11.22.33.44'])

# random session id (xid)
xid = pack('L', randrange(0, 2**32 - 1 ))

# setup socket
s = socket(AF_INET, SOCK_DGRAM)
s.bind(('0.0.0.0', 68))
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)

request = \
'\x01\x01\x06\x00' \
+ xid \
+ ''.ljust(20, '\x00') \
+ chaddr.ljust(16, '\x00') \
+ ''.ljust(192, '\x00') \
+ '\x63\x82\x53\x63' \
+ '\x35\x01\x03' \
+ '\xff'
s.sendto(request, ('255.255.255.255', 67))

# listen for dhcp packets for max 2.5 seconds
status = "OK - No rogue dhcp servers detected"
r = 0
s.settimeout(2.5)
while 1:
try:
buf, (ip, port) = s.recvfrom(65565)
except:
break
opcode, = unpack_from('B', buf)
if not (ip in whitelist and opcode == 0x02):
r = 2
status = "CRITICAL - Rogue dhcp server detected on IP-addr: " + ip
break

s.close()
print status
exit(r)


Monday, December 21, 2009

Thunderbird 3: awful search

The new search feature in Thunderbird 3 is horrible! It is hard to get an overview on this new layout, which can only contain a very limited amount of results. The idea of caching messages in a local database for faster search is good, but quite late... I would have prefered the classic search result view (which is what you expect from a mail program), but with the new cached backend.

Update: just noticed that it is possible to click the little magnifying glass in the input field and choose "Subject, From, or Recipient filter" to get the old style search back!

Update again: looks like the the horrible search has been dropped in version 3.1 :-)

Sunday, October 18, 2009

Raising / throwing custom exceptions in MySQL

I failed to find an official way to explicitly raise or throw exceptions in stored procedures in MySQL.

My workaround works by calling an undefined function with a meaningful name for an error.

For example:

DROP TRIGGER IF EXISTS users_before_insert;
DROP TRIGGER IF EXISTS users_before_update;
DROP PROCEDURE IF EXISTS validate_password;

delimiter $$
CREATE PROCEDURE validate_password (IN passwd VARCHAR(64))
BEGIN
IF LENGTH(passwd) < 5 THEN
CALL TRIGGER_DUMMY_INVALID_PASSWORD;
END IF;
END$$

CREATE TRIGGER users_before_insert BEFORE INSERT ON users
FOR EACH ROW
BEGIN
CALL validate_password(NEW.password_cleartext);
END$$

CREATE TRIGGER users_before_update BEFORE UPDATE ON users
FOR EACH ROW
BEGIN
CALL validate_password(NEW.password_cleartext);
END$$
delimiter ;


Most of the code in the specific example above was actually written by my colleague Per Fuglsang Møller.

Saturday, December 27, 2008

Configuration files: defaults or from scratch?

Up until recently I was a big fan of throwing away configuration files bundled with software such as apache, freeradius, etc., and write one from scratch to ensure i understood every single line.

My new approach is to leave configuration files at the defaults as much as possible. This makes it possible for other administrators to sit down and start editing the file and recognize the structure from other setups. It also makes it easier for package management systems to make diffs and indicate what has changed in new versions of the default configuration files when updating software (at least this is how Portage in Gentoo works).

A big disadvantage of this second approach is however, that it makes it difficult to get an overview of the configuration.

Which approach is best?

Friday, December 26, 2008

Netbeans and PHP projects over network shares

While trying to edit a bunch of existing PHP files in NetBeans, I had a little struggle getting the project set up correctly in NetBeans. There exists a project type called “PHP Application with Existing Sources”, and there exists a “Put NetBeans metadata into a separate directory”, but this latter feature does not work as I expected. If I try to set source directory to the Windows network share where my PHP scripts reside, and set metadata directory to a local directory to avoid filling the network share with metadata specific to this particular computer, NetBeans gives the error “Project and Source directories cannot be relativized”. It expects source and metadata directory to be on the same logical drive, or in the same network share.

To overcome this I created a symlink in my homedir on my server (a Linux box), pointing to the directory containing the PHP scripts. I could then set the source code folder to \\myserver\homes\mySymlink, and metadata folder to \\myserver\homes\tmp\netbeansjunk.
Hope this is useful to someone...