#!/usr/bin/perl # This script automatically runs: # # monkeysphere-authentication update-users # # every time it detects a change in an authorized_keys or authorized_user_ids # file. The update-users command operates on the username that owns the file # that was updated. # # The list of files to monitor is generated from the AUTHORIZED_USER_IDS and # RAW_AUTHORIZED_KEYS variables found in # /etc/monkeysphere/monkeysphere-authentication.conf and expanded using a list # of users on the system. # # Additionally, the /var/lib/monkeysphere/user-update/lastchange file is # monitored. If a change is made to that file, the list of files to monitor is # re-generated based on a fresh listing of users. If you run a hook on user # creation and deletion that generates a file in this directory, you can ensure # that the list of files to monitor is always up-to-date. # # On debian system you can install required perl modules with: aptitude install # libfile-changenotify-perl libfile-spec-perl libconfig-general-perl # # This script is designed to run at system start and should be run with root # privileges. # # File::ChangeNotify is cross platform - it will choose a sub class for # monitoring file system changes appropriate to your operating system (if you # are running Linux, liblinux-inotify2-perl is recommended). use strict; use File::ChangeNotify; use File::Basename; use File::Spec; use Config::General; my $user_update_file = '/var/lib/monkeysphere/user-update/lastchange'; my $debug = 0; sub debug { if ($debug eq 1) { print $_[0]; } } sub get_watch_files() { my @watch_files; my %key_file_locations = get_key_file_locations(); # get list of users on the system while((my $name,my $passwd,my $uid,my $gid,my $gcos,my $dir,my $shell,my $home) = getpwent( )){ while (my ($key, $file) = each (%key_file_locations)) { $file =~ s/%h/$home/; $file =~ s/%u/$name/; push(@watch_files,$file); } } endpwent(); push(@watch_files,$user_update_file); return @watch_files; } sub get_key_file_locations { # set defaults my %key_file_locations; $key_file_locations{ 'authorized_user_ids' } = '%h/.monkeysphere/authorized_user_ids'; $key_file_locations{ 'authorized_keys' } = '%h/.ssh/authorized_keys'; # check monkeysphere-authentication configuration my $config_file = '/etc/monkeysphere/monkeysphere-authentication.conf'; if (-f $config_file) { if (-r $config_file) { my %config; %config = Config::General::ParseConfig($config_file); if (exists $config{'AUTHORIZED_USER_IDS'}) { $key_file_locations{'authorized_user_ids'} = $config{'AUTHORIZED_USER_IDS'}; } if (exists $config{'RAW_AUTHORIZED_KEYS'}) { $key_file_locations{'authorized_keys'} = $config{'RAW_AUTHORIZED_KEYS'}; } } } return %key_file_locations; } sub get_watcher { my @filters; my @dirs; my(@files) = get_watch_files(); for my $file (@files) { my $dir = dirname($file); if ( -d $dir && !grep $_ eq $dir, @dirs ) { debug "Watching dir: $dir\n"; push(@dirs,$dir); my $file = basename($file); if ( !grep $_ eq $file, @filters ) { debug "Adding file filter: $file\n"; push(@filters,$file); } } } # create combined file filters to limit our monitor my $filter = '^(' . join("|",@filters) . ')$'; # return a watcher object return my $watcher = File::ChangeNotify->instantiate_watcher ( directories => [ @dirs ], filter => qr/$filter/, ); } sub watch { my $watcher = get_watcher(); while ( my @events = $watcher->wait_for_events() ) { my @users; for my $event (@events) { if($event->path eq "$user_update_file") { debug "Reloading user list"; $watcher = get_watcher(); } else { # if user deleted, file might not exist if( -f $event->path) { my $username = getpwuid((stat($event->path))[4]); if ( !grep $_ eq $username, @users ) { push(@users,$username); } } } } for my $user (@users) { my @args = ('u',$user); debug "Updating user: $user"; system 'monkeysphere-authentication', @args; } } } watch();