Monday, May 21, 2007

The Final Word on AFS PAGs and Services

Yeah... right. But for now (hopefully) (maybe).

Anyway, what I did was move pam_krb5 and pam_afs_session out of /etc/pam.d/common-* and ONLY put it in PAM stacks that need it. That would be dovecot, ssh, login and passwd. So now if you ssh to the server, you have a PAG. If you sudo -s, you have the same PAG. If you su, you have the same PAG. So start a new pagsh (this is important, if you don't, your unprivileged user will get the tokens and when you log out, pam_afs_session will destroy them). Now you can su - www-data -c 'k5start ...' and then 'apache2ctl start' and it works because Apache starts with the same PAG.

You can run apache2ctl graceful and restart from a shell with any PAG since it does not start the master (root) apache2 process (which has the original PAG), but if you need to fully restart Apache (e.g. stop/start) you'll need to start a new PAG and restart k5start under the new PAG.

So what I've done is gotten rid of the wrapped postfix/local and the foregrounded Dovecot and just wrapped their init scripts to run the start/restart methods inside a pagsh.

More later? Dunno.

Wednesday, May 16, 2007

AFS and Apache

Having sorted out mail on AFS, I moved on to Apache on AFS (or more appropriately, with access to AFS).

This ended up being a problem since Apache handles privileges different than Postfix and Dovecot. The way I had my PAM stack set up, pam_afs_session.so was getting AFS PAGs when I su'd, meaning that su'ing to the Apache user to k5start would get me nowhere since the AFS tokens I got would be associated with a PAG that the server itself would not be running as.

Once I got a good handle on how PAGs work, I got to work disabling them. Reason being that unless you authenticate through AFS directly instead of using your Kerberos credentials and the afs service ticket to get tokens, there's no security offered in using PAGs. The whole point of a PAG is so someone with root on an AFS client box can't su to a user and have access to their tokens. But Kerberos offers no such functionality with tickets, so if a user has tickets and I su to them, I can just aklog and get my own tokens as them. The only way I can see a user preventing a local superuser from getting tokens is to get both tickets and tokens, then destroy the tickets (so they have tokens but no tickets from which to get new tokens).

If I'm misunderstanding this and disabling PAGs has greater security implications, please let me know!

So back to work... I set the nopag option on pam_afs_session.so in /etc/pam.d/common-auth and /etc/pam.d/common-session. Now I wasn't getting PAGs (yay!), but IMAP broke (boo!).

So I copied the contents of /etc/pam.d/common-* to /etc/pam.d/dovecot, re-enabling PAG for dovecot by removing nopag (but leaving it in common-*).

So I would think that if dovecot needs PAGs in this manner, postfix/local would too. But it doesn't. And I'm not sure why. I have a couple guesses... like dovecot is spawning a separate imap process as you to hand you off to once you've authenticated, so that process needs the PAG, whereas local is all done in a single process. But then by that logic, procmail shouldn't work? Or, dovecot actually auth's you via PAM where local doesn't. That could be it...

My brain hurts, I'm going home.

Tuesday, May 15, 2007

AFS, Postfix, Dovecot and Maildirs

UPDATE: Most of this is still valid, but read this first to see what I've learned about needing PAGs.

Okay, here's the deal. Maildir works by using link()/unlink() to move mail around from the new/cur/tmp dirs. This is a problem because AFS doesn't allow link() across dirs Doing so would break ACLs. However, you can safely use rename() with Maildirs on AFS because it's atomic, which is the whole reason Maildir uses link()/unlink() in the first place.

Originally I didn't have any problems with link()/unlink() because I didn't let the Postfix local delivery agent (local) deliver my mail - it passed it off to procmail, which already happens to use rename() when dealing with Maildir (which is technically incorrect behavior).

Here's how you can get it to work:
  1. Create a user principle in Kerberos for postfix and one for dovecot. Export as keytabs. Store them on the mail server somewhere. You could probably use a single principle for this, but I like the idea of having two so users can remove privs from dovecot if they don't check their mail via IMAP.
  2. Make a few changes in dovecot.conf. First, keep indexes out of AFS and disable link() copies:

    mail_location = maildir:/afs/cell/home/%u/Maildir:INDEX=/var/lib/dovecot-index/%u
    maildir_copy_with_hardlinks = no


    Next, disable mmap and enable dotlocks. I would think you shouldn't need these but this is what I ended up with that worked. Test yourself and see:

    mmap_disable = yes
    dotlock_use_excl = yes
    lock_method = dotlock


    I ended up using the following args for passdb pam {}to ensure pam_afs_session gets hit:

    args = session=yes setcred=yes dovecot

  3. k5start dovecot in the foreground (k5start backgrounds the whole thing):

    k5start -U -f /etc/dovecot/dovecot.keytab \
    -t -b -K 10 -- /usr/sbin/dovecot -F

  4. Get the Postfix source (as I use debian, I just grabed the source package from APT and built it that way). Edit src/local/maildir.c and change the sane_link() calls to rename(), and comment out the call to unlink(). Install Postfix. WARNING: You shouldn't modify this if your Postfix also delivers to non-AFS Maildirs, as rename() on most non-AFS filesystems is NOT atomic. If you need to do that, checking to see if you're in /afs and then using the right syscall should be trivial.
  5. Rename /usr/lib/postfix/local (or wherever it is on your system). I mv'd it to local.wrapped
  6. Make a new file called local, give it the same permissions/owernship as local.wrapped, and then wrap local.wrapped as such:

    #!/bin/sh
    k5start -U -f /etc/postfix/postfix.keytab \
    -K 10 -t -- /usr/lib/postfix/local.wrapped \
    "$@"


  7. Set ACLs on Maildirs for postfix/dovecot:

    find /afs/path/to/Maildir -type d -exec \
    fs setacl {} postfix rlidwk dovecot rlidwk \;

For a while there, I considered just sticking the Maildirs locally on the mail server instead of in AFS homedirs. But there are benefits to having Maildirs in the AFS: Direct access to grep them, moving sub-maildirs around so you can archive them to somewhere outside your Maildir, and of course, direct access via command line mailreaders like mutt.