Last night I got inspired to add back the through-the-web creation and deletion of mailing lists. I've now got this working for Postfix and can work with other MTAs with a little help from y'all. I will soon be checking all this code into the 2.1 codebase, so watch mailman-checkins shortly. (And hey, it only took 24 hours from inception to completion! :).
Apologies in advance for the length of this message.
First, there is a new pseudo-role[1] called `list creator'. There is a separate, global list creator password, similar to but different than the site admin password. This is because list creation is a site-wide operation, but I don't want to have to give out the site admin password to someone who may only have list creation duties. Needless to say, the site admin can create lists through the web too. You set the list creator's password by using mmsitepass with the -c option.
Let's say Mailman is installed at http://yoursite.com/mailman, then the list creation page is at http://yoursite.com/mailman/create which is linked to from the admin overview page (but not the listinfo overview page).
The create page requires you to enter the name of your list, the email address of the initial list owner, the initial list password (with confirmation), and the list creator's password. There is then a "Create" button to submit the form.
Assuming everything checks out, the new list is created, and the results page gives you three links to follow from there (go to the list's info page, the list's admin page, or create another list).
Deleting a list is done from the list's admin page. There is now another link under "Other Administrative Activities" that says "Delete this list (requires confirmation)". Click on that and you're brought to a page for confirmation of the list deletion operation. You have a radio button to choose whether the archives should be deleted or not (the default is not), and you're prompted for the list admin password[2]. There's a link to cancel the deletion and return to the list's admin page, and a button to actually do the list deletion.
For bonus, the site administrator can inhibit the ability for individual list owners to delete their lists through the web by setting OWNERS_CAN_DELETE_THEIR_OWN_LISTS = 0 in mm_cfg.py. Do this, and the link is not shown in the "Other Administrative Activities" list, and the rmlist cgi will error out every time. The current default for OWNERS_CAN_DELETE_THEIR_OWN_LISTS is 0, but that may change to 1 before the final release. The disadvantage is that with this variable set to 0, list deletion must be done via the command line script.
Now, how to integrate this with MTAs? One reason why ttw list creation and deletion hasn't been (re-)added to Mailman until now is that you typically have to do some manual and difficult crud like edit an /etc/aliases file and run `newaliases' (as root!). I've figured a way around this with Postfix, and of course Exim can be configured to automatically recognize new mailing lists, so I figured it was time to do it. I'm hoping that Sendmail, Qmail, and other MTA users amongst yourselves will contribute the code to glue this together for other mailers.
Here's how I solved it for Postfix; this is outlined in a new README.POSTFIX file.
Postfix has a configuration variable called alias_maps' which tells it where to look for local delivery address associations. It has another variable called
alias_databases' which tells it which files
to rebuild when invoked as newaliases. For each of these you can
specify the type of map database the file is kept as. One of these
choices is `hash', which is really a BSD dbhash file. Python has a
dbhash module which nicely handles reading and writing dbhash files
(and it should be enabled by default in Python 2.x, if your system has
Berkeley DB installed, as most Linux distros ought to).
It's moderately well-published what Postfix expects as entries in the dbhash (and it's easy to figure out by dumping a newaliases generated .db file) so, when creating a new list, Mailman can add the necessary keys and values to make Postfix happy. Let's say Mailman is installed as /home/mailman and writes its new list alias entries to the dbhash file at /home/mailman/data/aliases.db. By adding "hash:/home/mailman/data/aliases" to your Postfix's alias_maps variable, Postfix will automatically deliver to your new list. Deleting is as simple as removing the keys from the dbhash.
Note that you do /not/ want to add this file to alias_databases since newaliases won't be touching it.
So this works great, but there's a catch! Postfix will invoke the filter programs under the uid of the owner of the aliases.db file, unless that's root, in which case it'll invoke it as the user defined in the default_privs variable (by default `nobody'). And of course the gid has to match what you specify in --with-mail-gid or Mailman's mail wrapper will complain.
The trick is to touch the alias.db file as root, set the group owner to mailman, and make sure the file is user and group writable. Now, when Mailman adds new keys to aliases.db, the user ownership will remain as root, so Postfix invokes it correctly as nobody. But because aliases.db is group-owned by mailman, the cgi processes can write to the file. And no setuid-root script in sight. I've tested this and it works like a charm.
(Of course, all this is described in cookbook form without the gory details in README.POSTFIX. Also, I like this approach much better than the luser_relay hack I posted about a while ago.)
There's one last bit of glue, and here's where you come in (I'm speaking to the one of you who is still reading this. :). There's a new variable in Defaults.py.in called MTA which must point to a module in the Mailman/MTA directory. This implements the MTA-specific operations needed when creating or deleting a list. The API is that this module should provide two functions: create() and remove() both of which take a MailList object. They should do whatever is necessary to inform the MTA that it's alias database has changed. For Postfix it's really not a lot of code[3].
For Exim, I predict "MTA = None" in mm_cfg.py will Do The Right Thing, since nothing special has to be done. I've no idea at this time what Sendmail, Qmail, or any other MTA will require, and I'm hoping those of you who use those mailers will be able to donate a module.
Phew, that's it. I need sleep.
I'm very interested in getting some feedback, especially for those hearty souls who can check out the current codebase, and give it a whirl. I'm no doubt forgetting some important details, but it sure has been fun. :)
Enjoy, -Barry
[1] I call it a pseudo-role because eventually this will be a role that can be given to specific users (once there's a Real User Database).
[2] Because list deletion is not handled by the admin.py cgi script, it isn't protected by the normal admin login screen. I could (and may) add this extra authentication step, but I'll probably still keep the list password requirement on the deletion page as a strong confirmation of the list owner's intention.
[3] There's one caveat: because I don't want to have to include a setuid-root script, the Postfix.py module doesn't call `postfix reload'. This command has to be done as root. The tradeoff is that Postfix will take about a minute to recognize its alias database has changed. To me that's an acceptable limitation.