From 86a0f2e2d64c035e30dc4dc9634de8b1fb1e5c39 Mon Sep 17 00:00:00 2001 From: mwolson_admin Date: Thu, 17 Jul 2008 10:53:55 -0400 Subject: [PATCH] Add freeze, frozen_shell, hcoop-kprop. --- freeze | 363 +++++++++++++++++++++++++++++++++++++++++++++++++++ frozen_shell | 20 +++ hcoop-kprop | 15 +++ 3 files changed, 398 insertions(+) create mode 100755 freeze create mode 100755 frozen_shell create mode 100755 hcoop-kprop diff --git a/freeze b/freeze new file mode 100755 index 0000000..5f0c282 --- /dev/null +++ b/freeze @@ -0,0 +1,363 @@ +#!/usr/bin/perl + +# +# Purpose: freeze user (cancel user services except email), or unfreeze user. +# +# Usage (RUN AS _ADMIN USER ON DELEUZE WITHOUT SUDO): +# +# Display frozen users or details for one user (one user implies -verbose): +# freeze [user], OR +# freeze --action list [--verbose] | freeze -a l [-v | user] +# +# Freeze user: +# freeze -a f user +# +# Unfreeze: +# freeze -a u user +# +# +# How it works: +# +# Script invokes a list of modules, where each module knows how to +# implement and unimplement a specific restriction. Implemented modules +# should be listed in @modules array or they won't get called. Admin +# can override list of modules with --modules=one,two,three. +# +# Modules execute in the order as specified for freeze, and in reverse +# order for unfreeze. +# +# Module gets called as &module($action, $user) . The proper way to +# test for which action is requested is as shown below. (Note that +# module adds or removes itself to the list of modules that ran on the user). +# +# if ($a =~ /^f/i) { +# ... freeze ... +# push @{ $$store{$u}{modules} }, 'MODULE'; +# } elsif ($a =~ /^u/i) { +# ... unfreeze ... +# @{ $$store{$u}{modules} } = grep {!/^MODULE$/} @{ $$store{$u}{modules} }; +# } +# +# Also each system-modifying action should be wrapped in if (!DRY) as shown: +# +# if (!DRY) { +# system(qq{SOME COMMAND}) +# } else { +# warn qq|SOME COMMAND| +# } +# +# User is valid system username, and user's getent entry is prepared and +# retrievable through @user array, should you need some of its info. +# +# Module can save all persistent data to $$store{$user}{$modulename}. For +# example, after cron module removes user from all cron.allows, it +# registers the machines where user was removed to +# @{ $$store{$u}{cron} }, so that it can revert it back if user is +# unfreezed. +# +# Module 'record' creates or deletes initial user entry in $$store. +# If you create a new module that will use the store (announce it's +# hash key by creating it empty in record(). +# +# For additional help, here's how the stored hash might look like: +# +# +# $store = { +# user1 => { +# date => 'Sun Jun 29 18:45:43 CEST 2008', +# getent => [qw/docelic 1000 1000 DavorOcelic /home/docelic /bin/bash] +# +# modules => [qw/login domtool cron slay/], # (modules that ran) +# domains => [qw/spinlock.hr test.hr/], # (domains that were removed) +# cron => [qw/mire/], # (hosts where cron.allow entry was removed) +# }, +# user2 => { +# ... +# }, +# ... +# ... +# ... +# } +# +# +# Wiki page relating to this script is http://wiki.hcoop.net/MemberFreezing +# +# Davor Ocelic, docelic@hcoop.net, Sun Jun 29 18:41:02 CEST 2008 +# +# + +use warnings; +use strict; + +use Storable qw/lock_nstore lock_retrieve/; +use Getopt::Long qw/GetOptions/; + +use constant DEBUG => 1; +use constant DRY => 1; +use constant STORE => "/tmp/store"; +use constant DEFAULT_SHELL => '/bin/bash'; +use constant FROZEN_SHELL => '/afs/hcoop.net/common/etc/scripts/frozen_shell'; +use constant PUBLIC_ACCESS => [qw/mire/]; +use constant RUN_SERVER => 'handgun'; + +my $store = {}; # cached info +my $action = 'list'; # list, freeze, unfreeze +my $verbose = 0; # 0/1 (print which modules were applied to user in freezing) +my $force = 0; # 0/1 (force action even if user already freezed/unfreezed) +my $user; # who to freeze/unfreeze +my @user; # getent passwd entry for user +my $modules; # list of freeze/unfreeze actions to take +my @modules; # modules, possibly overriden by split /,\s+/, $modules + +# Keep modules listed in order of application, honoring possible dependencies. +@modules = (qw/record login domtool slay/); + +unless ( GetOptions ( + 'do|d|a=s' => \$action, + 'verbose|v!' => \$verbose, + 'force!' => \$force, + 'modules|m=s' => \$modules, +)) { die "Error parsing options: $!\n" } + +$user = shift ; + +if ( -e STORE ) { + $store = lock_retrieve(STORE); +} else { + warn "No '" . STORE . "', skipping load.\n"; +} + +if ( `hostname` ne RUN_SERVER . "\n" ) { + die "Please run script on " . RUN_SERVER . "\n"; +} + +if ( $action =~ /^l/i ) { + while (my ($k,$v) = each %$store ) { + if (! $user or $user eq $k ) { + print "$k $$v{date}\n"; + print " @{$$v{modules}}\n" if $verbose or $user; + } + } + exit 0; +} + +$user or die "Must specify user to freeze/unfreeze. Exiting.\n"; +$user =~ /^[a-z0-9]+$/ or die "Invalid username (not [a-z0-9]+).\n"; +@user = split(/:/, `getent passwd $user`); +@user or die "No such user? (getent passwd USER empty.)\n"; +chomp $user[$#user]; + +if ( $action !~ /^[fu]/i ) { + warn "Unknown action: use -a [list (l)|freeze (f)|unfreeze (u)]\n"; +} + +if ( $action =~ /^f/i ) { + if ( exists $$store{$user} ) { + warn "User already frozen since $$store{$user}{date}.\n"; + if (! $force) { + die "Exiting.\n"; + } + } +} + +elsif ( $action =~ /^u/i ) { + if (! exists $$store{$user} ) { + warn "User not frozen in the first place.\n"; + if (! $force) { + die "Exiting.\n"; + } + } +} + +else { + warn "How did you get through?\n"; + die; +} + + +if ($modules) { @modules = split /[,\s+]/, $modules; } +for ( $action =~ /^u/i ? reverse @modules : @modules ) { + no strict 'refs'; + print "Module: $_\n"; + &{ $_ }($action, $user); +} + +lock_nstore $store, STORE; + + +########################################################################### +# Helpers below + +# GETENT: +# 0 1 2 3 4 5 6 +# docelic:x:10235:65534:docelic:/afs/hcoop.net/user/d/do/docelic:/bin/bash + +sub record { + my ($a, $u) = @_; + $a =~ /^f/i and $$store{$u} = { + date => scalar localtime, + getent => [ @user ], + modules => [], + domains => [], + cron => [], + }; + $a =~ /^u/i and delete $$store{$u}; +} + +sub login { + my ($a, $u) = @_; + + if ($a =~ /^f/i) { + if ( $user[6] ne DEFAULT_SHELL ) { + $$store{$u}{shell} = $user[6] unless $user[6] eq FROZEN_SHELL; + } + + + if ( -e "$user[5]/.loginshell" ) { + if (!DRY) { + unlink "$user[5]/.loginshell" or warn "unlink: $!" + } else { + warn qq{unlink $user[5]/.loginshell\n}; + } + } + + if (!DRY) { + symlink FROZEN_SHELL, "$user[5]/.loginshell" + or warn "symlink: $!"; + } else { + warn qq{symlink FROZEN_SHELL, "$user[5]/.loginshell"\n} + } + + push @{ $$store{$u}{modules} }, 'login'; + + if ( -x "/usr/sbin/nscd" ) { system("sudo /usr/sbin/nscd -i passwd") }; + } + + elsif ($a =~ /^u/i) { + if ( $$store{$u}{shell}) { + if ( -l "$user[5]/.loginshell" or -e "$user[5]/.loginshell" ) { + if (!DRY) { + system("rm '$user[5]/.loginshell'"); + } else { + warn qq{system("rm '$user[5]/.loginshell'")\n}; + } + } + if (!DRY) { + symlink($$store{$u}{shell}, "$user[5]/.loginshell") + or warn "symlink: $!"; + } else { + warn qq|symlink($$store{$u}{shell}, "$user[5]/.loginshell")\n|; + } + } + + @{ $$store{$u}{modules} } = grep {!/^login$/} @{ $$store{$u}{modules} }; + + if ( -x "/usr/sbin/nscd" ) { system("sudo /usr/sbin/nscd -i passwd") }; + } +} + + +sub domtool { + my ($a, $u) = @_; + + # XXX handle all types of domtool privs, not just domains + # XXX how to restart services after that? + + if ($a =~ /^f/i) { + my $domains = `domtool-admin perms docelic | grep '^domain: '`; + chomp $domains; + my @domains = split / +/, $domains; + + for (@domains) { + push @{ $$store{$u}{domains} }, $_; + if (!DRY) { + system("domtool-admin rmdom $_") + } else { + warn qq|system("domtool-admin rmdom $_")\n| + } + } + + if (!DRY) { + system("domtool-rmuser $_") + } else { + warn qq|system("domtool-rmuser $_"\n| + } + + push @{ $$store{$u}{modules} }, 'domtool'; + } + + elsif ($a =~ /^u/i) { + if (!DRY) { + system("domtool-adduser $_") + } else { + warn qq|system("domtool-adduser $_")\n| + } + + for ( @{ $$store{$u}{domains} } ) { + if (!DRY) { + system("domtool-admin grant $u domain $_") + } else { + warn qq|system("domtool-admin grant $u domain $_")\n| + } + } + + @{ $$store{$u}{modules} } = grep {!/^domtool$/} @{ $$store{$u}{modules} }; + } +} + + + +sub cron { + my ($a, $u) = @_; + + if ($a =~ /^f/i) { + for ( PUBLIC_ACCESS ) { + if ( qx{ssh -K $_ grep -E '^$u\$' /etc/cron.allow }) { + push @{ $$store{$u}{cron} }, $_; + + if (!DRY) { + qx{ssh -K $_ perl -ni -e 'print unless /^\$/' /etc/cron.allow } + } else { + warn qq{ssh -K $_ perl -ni -e 'print unless /^\$/' /etc/cron.allow\n} + } + } + } + + push @{ $$store{$u}{modules} }, 'cron'; + } + + elsif ($a =~ /^u/i) { + for ( @{ $$store{$u}{cron} } ) { + if (!DRY) { + qx{ssh -K $_ sh -c 'echo $u >> /etc/cron.allow'}; + } else { + warn qq{ssh -K $_ sh -c 'echo $u >> /etc/cron.allow'\n}; + } + } + + @{ $$store{$u}{modules} } = grep {!/^cron$/} @{ $$store{$u}{modules} }; + } +} + + +sub slay { + my ($a, $u) = @_; + + if ($a =~ /^f/i) { + for ( PUBLIC_ACCESS ) { + if (!DRY) { + qx{ssh -K $_ slay $u}; sleep 5; qx{ssh -K $_ slay -9 $u}; + } else { + warn qq|ssh -K $_ slay $u; sleep 5; ssh -K $_ slay -9 $u\n| + } + } + + push @{ $$store{$u}{modules} }, 'slay'; + } + + elsif ($a =~ /^f/i) { + @{ $$store{$u}{modules} } = grep {!/^slay$/} @{ $$store{$u}{modules} }; + } +} + + diff --git a/frozen_shell b/frozen_shell new file mode 100755 index 0000000..01c4e7a --- /dev/null +++ b/frozen_shell @@ -0,0 +1,20 @@ +#!/bin/sh + +echo " + +Please pay your HCoop dues to have your access restored. + +All information on making a payment is available on our Members Portal, + + https://members.hcoop.net/ + +Contact HCoop system administrators at admins@hcoop.net if you +cannot access the Portal. + +Thank you, +HCoop + +"; + +exit 0; + diff --git a/hcoop-kprop b/hcoop-kprop new file mode 100755 index 0000000..71d7850 --- /dev/null +++ b/hcoop-kprop @@ -0,0 +1,15 @@ +#!/bin/bash -e + +# +# It is important that admins receieve notification of any errors that +# occur when running this; please don't indiscriminately send logs to +# /dev/null. +# + +export PATH=$PATH:/usr/sbin:/sbin + +kdb5_util dump /var/lib/krb5kdc/slave_datatrans +kprop krunk.hcoop.net \ + 2>&1 | grep -v 'Database propagation to krunk.hcoop.net: SUCCEEDED' + + -- 2.20.1