File: monkeysphere-monitor-keys

package info (click to toggle)
monkeysphere 0.43-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 844 kB
  • sloc: sh: 1,483; perl: 1,007; ansic: 671; makefile: 92
file content (157 lines) | stat: -rwxr-xr-x 5,096 bytes parent folder | download | duplicates (5)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/perl

# This script automatically runs:
#
#   monkeysphere-authentication update-users <user>
#
# 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).

# FIXME: does this handle revocations and re-keying?  if a sysadmin
# switches over to this arrangement, how will the system check for
# revocations?  Scheduling a simple gpg --refresh should handle
# revocations.  I'm not sure how to best handle re-keyings.

use strict;
use warnings;
use File::ChangeNotify;
use File::Basename;
use File::Spec;
use Config::General;

my $user_update_file = '/var/lib/monkeysphere/user-update/lastchange';
my %watch_files;

my $debug = 0;
if (defined($ENV{MONKEYSPHERE_LOG_LEVEL}) &&
    $ENV{MONKEYSPHERE_LOG_LEVEL} =~ /^debug/i) {
  $debug = 1;
}

sub debug {
  printf STDERR @_
    if ($debug eq 1);
}

sub set_watch_files() {
  my %key_file_locations = get_key_file_locations();
  # get list of users on the system
  while(my ($name, $passwd, $uid, $gid, $gcos, $dir, $shell, $home) = getpwent()) {
    while (my ($key, $file) = each (%key_file_locations)) {
      $file =~ s/%h/$home/;
      $file =~ s/%u/$name/;
      $watch_files{ $file } = $name;
    }
  }
  endpwent();
  $watch_files{ $user_update_file } = '';
}

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;

  set_watch_files();
  for my $file (%watch_files) {
    my $dir = dirname($file);
    if ( -d $dir && !grep $_ eq $dir, @dirs ) {
      debug("Watching dir: %s\n", $dir);
      push(@dirs,$dir);
      my $file = basename($file);
      if ( !grep $_ eq $file, @filters ) {
        $file = quotemeta($file);
        debug("Adding file filter: %s\n", $file);
        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\n");
        $watcher = get_watcher();
      } else {
        # if user deleted, file might not exist
        # FIXME - m-a u returns an error if the username
        # doesn't exist. It should silently ensure that 
        # the generated authorized_keys file is deleted.
        # Once it's fixed, we should execute even if the 
        # file is gone.
        if( -f $event->path) {
          my $username = $watch_files { $event->path };
          $users{ $username } = 1;
        }
      }
    }
    for ((my $username) = each(%users)) {
      debug("Updating user: %s\n", $username);
      # FIXME: this call blocks until m-a u finishes running, i think.
      # what happens if other changes occur in the meantime?  Can we
      # rate-limit this?  Could we instead spawn child processes that
      # run this command directly?
      system('monkeysphere-authentication', 'update-users', $username);
    }
  }
}

watch();