I didn't see many living examples of how to do this, so I thought it might be useful to share.
In our system, we have an LDAP auth backend which can be broader than the mailboxes on a system. We didn't have any luck with using pam_groupdn in pam_ldap.conf, so it is useful to use the PAM module listfile. In pam.d/imap (same for pop or sieve) we would include: auth required pam_listfile.so onerr=fail item=user sense=allow file=/cyrus/mailmgmt/mysystemlist If you are not in this file list of users, but you have authenticated against the backend OK, you won't get in. Keeping that list of mailbox users updated is done by a cron running the perl script following: #!/usr/bin/perl -w # Maintain a list of valid mailboxes on mysystem for pam authentication purposes use strict; use Fcntl ':flock'; # Global variables for filenames, etc. my( $basedir ); $basedir = "/cyrus/mailmgmt"; my( $PWD ) = $ENV{'PWD'}; chdir ( $basedir ); # Other global variables my( %mysystemboxes, $now); # Get the mailbox list from mysystem %mysystemboxes = &get_mysystem_mailboxes( ); chdir( $PWD ) if ( $PWD ); exit 0; # # It's all subroutines from here on out # # # # Subroutine to get the mailbox list from mysystem. # sub get_mysystem_mailboxes( ) { my( @mysystemboxes ); # Get the list of mailboxes from mysystem.example.com @mysystemboxes = &get_mailbox_list( "localhost", "cyrusadm", "mypassword" ); if( grep { /^IMAP error:/ } @mysystemboxes ) { die "Error retrieving mailbox list from mysystem.\n@mysystemboxes\n"; } # Dump the mailbox list to a file open( SYSTEMBOXES, "> $basedir/mysystemlist " ) or die "Couldn't open file: $!\n"; foreach( @mysystemboxes ) { print SYSTEMBOXES "$_\n"; } print SYSTEMBOXES "cyrusadm\n"; close( SYSTEMBOXES ) or die "Couldn't close file: $!\n"; return %{ { map { $_ => 1 } @mysystemboxes } }; } # # # Subroutine for an IMAP connection to get a mailbox list from a server # sub get_mailbox_list( $$$ ) { use IMAP::Admin; my( $server, $uid, $pwd ) = @_; my( $client, $mailbox, @mailboxlist, @usernames, $username ); $client = IMAP::Admin->new( 'Server'=> "$server", 'Login' => "$uid", 'Password' => "$pwd", 'CRAM' => 0 ) or return "Couldn't create IMAP connection: $!\n"; @mailboxlist = $client->list( "user.*" ) or return "IMAP error: \n\t" . $client->error . "\n"; $client->close; foreach $mailbox ( @mailboxlist ) { push @usernames, ${ [ split( /\./, $mailbox ) ] }[1]; } @usernames = keys %{ { map { $_ => 1 } @usernames } }; return( @usernames ); } It would need some adjustment for different type of authentication or separator.
---- Cyrus Home Page: http://www.cyrusimap.org/ List Archives/Info: http://lists.andrew.cmu.edu/pipermail/info-cyrus/