Using Expect with sieveshell...
July 2019
Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
This site is an effort to share some of the base knowledge I have gathered through all this years working with Linux, FreeBSD, OpenBSD, Python or Zope, among others. So, take a look around and I hope you will find the contents useful.
Recent Entries
Recent Comments
Recent Trackbacks
OpenBSD (9 items)
BSD (0 items)
FreeBSD (19 items)
Linux (3 items)
Security (3 items)
Python (22 items)
Zope (13 items)
Daily (144 items)
e-shell (9 items)
Hacks (14 items)
PostgreSQL (3 items)
OSX (8 items)
Nintendo DS (0 items)
enlightenment (0 items)
Apache (3 items)
Nintendo Wii (1 items)
Django (24 items)
Music (12 items)
Plone (7 items)
Varnish (0 items)
Lugo (2 items)
Sendmail (0 items)
europython (7 items)
Cherokee (1 items)
self (1 items)
Nature (1 items)
Hiking (0 items)
uwsgi (0 items)
nginx (0 items)
cycling (10 items)
Networking (1 items)
DNS (0 items)

Syndicate this site (XML)

RSS/RDF 0.91

30 abril

Using Expect with sieveshell... provide passwords interactively

Yesterday I found an interesting task on my TODO list. I had to activate a sieve script like that one:

require "fileinto";

if header :contains "Subject" "[SPAM]" {
      fileinto "INBOX.SPAM";
else {
fileinto "INBOX";

(just put every message with the string [SPAM] into a predefined mail box (INBOX.SPAM))

If you have used sieve before, you should know of sieveshell, an interactive perl-based shell to manage such scripts. Using sieveshell, each user can manage it's own scripts, and the admin could manage scripts for every user.

[prunus] ~> sieveshell -u -a localhost
connecting to localhost
Please enter your password:
> help
  sieveshell [-u username] [-a authname] [-r realm] <server>

help             - this screen
list             - list scripts on server
put <filename> [<target name>]
               - upload script to server
get <name> [<filename>]
               - get script. if no filename display to stdout
delete <name>    - delete script.
activate <name>  - set a script as the active script
deactivate       - deactivate all scripts
quit             - quit

You can even use some kind of a batch mode to run commands directly, without entering the shell:

[prunus] ~> sieveshell -u -a --exec='list' localhost
connecting to localhost
Please enter your password:
bogom_filter_spam.txt  <- active script
[prunus] ~>

"Fine, I can create a little script to call the needed commands to activate the script for every user in the database" - That was my first thought, but I found a little problem about it, everytime I called sieveshell, it asked me for a password (the admin password in my case). And that was a real problem, as I needed to activate the script for more than 3000 email accounts.

Thnk the holy cow that people in #BSDcow always help me!

First, I needed a script that got a list of email address, and call sieveshell with the proper commands, something like:

# Script to automatically add and activate sieve
# scripts

for i in `ldapsearch -LL -H ldap://localhost -b",ou=Hosting,dc=pxgo,dc=es" -x "(uid=*)" | grep "mail:" | cut -f 2 -d ' '`
  echo "User $i, uploading script"
  /usr/local/bin/sieveshell -u $i -a root --exec='put /home/pxgo/bogom_filter_spam.txt' localhost
  echo "User $i, enabling script"
  /usr/local/bin/sieveshell -u $i -a root --exec='activate bogom_filter_spam.txt' localhost
  echo "User $i, script enabled"
/usr/local/bin/sieveshell -u $i -a root --exec='list' localhost

As you can see, OpenLDAP is the backend where user information is stored, so the script performs a query against the ldap server using ldapsearch and (with some grep and cut magic) it gets the list of avaliable email addresses. Then it goes through the list, calling sieveshell accordingly.

If I've used the script just like that, I should have to provide the admin password 3 times per user, which in my case is (3x3000=9000) 9000 times!. Impossible, for sure.

After some googling on sieveshell batch mode, I found some results in the official mailing list about a guy who wrotes a perl script to do the job, but that script have some dependencies I didn't want to install on my server. So that was not an option.

After a little more research I ended up talking with ajacoutot and betabug on #BSDcow. And they told me to use expect (and they helped me a lot understading and troobleshooting my tests).

Never used it before, but after some reading I got some basic knowledge about it. First, I needed to install it on my server, pretty easy using the ports collection:

[prunus] /usr/ports/lang/expect-devel> sudo make install clean

Then, I created an expect script, just in the same place I created the other one before, that gets the command I want to run (sieveshell), with the needed arguments, then it calls the command properly inside the expect environment, and provide the password automatically:

# Script to call the script that adds and
# activates sieve scripts in an unattended way

set Sieveshell [lindex $argv 0]
set User [lindex $argv 1]
set Auth [lindex $argv 2]
set Exec [lindex $argv 3]
set Host [lindex $argv 4]

spawn $Sieveshell -u $User -a $Auth --exec=$Exec $Host

expect "Please enter your password:"
send "XXXXX\n";

NOTE: the \n at the end of the password is needed so send sends the password, if you do not put that \n there, the password will be only echoed after the Please enter your password: prompt.

Once the expect script was created, I needed to modify the original script, to use this one instead of calling sieveshell directly:

# Script to automatically add and activate
# sieve scripts

for i in `ldapsearch -LL -H ldap://localhost -b",ou=Hosting,dc=pxgo,dc=es" -x "(uid=*)" | grep "mail:" | cut -f 2 -d ' '`
  echo "User $i, uploading script"
  ./sieveshell_expect /usr/local/bin/sieveshell $i root "put /home/pxgo/bogom_filter_spam.txt" localhost
  echo "User $i, enabling script"
  ./sieveshell_expect /usr/local/bin/sieveshell $i root "activate bogom_filter_spam.txt" localhost
  echo "User $i, script enabled"
  ./sieveshell_expect /usr/local/bin/sieveshell $i root "list" localhost

Of course, it would be great if we could provide all commands inside a single call to sieveshell, but seems that this is not posible (as far as I know), and it would be better if I had more time to put some checks inside the scripts (know they seem pretty ugly/insecure), but hey, that's a quick hack for desperate sysadmins!

Posted by wu at 13:48 | Comments (1) | Trackbacks (0)
<< Macports and python 2.5 | Main | OpenBSD 4.3 released >>
Re: Using Expect with sieveshell...

Congratulations Man!!!!
Works perfectly, I had the same problem to create a filter spam to my users, and your tips help me a lot!!!!

It's insane put 15000 times my password! lol


Posted by: Jefferson at enero 23,2015 15:20
Please send trackback to:
There are no trackbacks.
Post a comment