Add misc. scripts

This commit is contained in:
2026-04-13 01:15:07 +09:00
commit 65f8868364
14 changed files with 682 additions and 0 deletions

5
README.md Normal file
View File

@@ -0,0 +1,5 @@
# spook
This repository contains all sorts of code snippets, scripts and timed jobs that haunts our machine park, as well as any packaging and configuration needed to make them run.
Some of these scripts used to be part of the salt-stack configuration repository, but have since been moved here.

View File

@@ -0,0 +1,4 @@
#! /bin/bash
[ `grep -c 'retry time not reached for any host after a long failure period' /var/log/exim4/mainlog` -gt 100 ] && grep 'retry time not reached for any host after a long failure period' /var/log/exim4/mainlog | tail | mail -s "Possible mail loop detected" root
exit 0

45
make-homes/make-homes.pl Executable file
View File

@@ -0,0 +1,45 @@
#! /usr/bin/perl
# Går gjennom passwd.pvv og oppretter alle hjemmekataloger som mangler.
use strict;
use warnings;
use File::Basename;
sub execute {
if (system(@_) != 0) {
die "Failed to execute " . join(" ", @_);
}
}
my $passwd = "/etc/passwd.pvv";
my $homes_created = 0;
open (my $passwd_fd, $passwd) or die "Unable to open $passwd: $!";
while (<$passwd_fd>) {
chomp;
my ($user, undef, $uid, $gid, undef, $homedir, $shell) = split(":");
# Ignorer brukere som uansett ikke får lvov til å logge inn
next if $shell eq "/bin/sperret" || $shell eq "/bin/msgsh" || $shell eq "/bin/false";
# Prefix med /export, som er lokal path på NFS-serveren
$homedir = "/export" . $homedir;
# Only create homedir if it is missing, and it would have been exported from here
if (-d dirname($homedir) && !-d $homedir) {
print "Oppretter hjemmekatalog for $user: $homedir\n";
$homes_created = 1;
execute("mkdir", "-p", "-m", "711", $homedir);
execute("cp -r /local/skel/usr/.??* $homedir");
execute("chown", "-R", "$uid:$gid", $homedir);
execute("find", $homedir, "-type", "f", "-exec", "chmod", "600", "{}", "+");
execute("find", $homedir, "-type", "d", "-exec", "chmod", "700", "{}", "+");
execute("chmod", "711", $homedir); # Må ha execute, så ~/web-docs virker
}
}
if ($homes_created) {
execute("/local/quota/makeexportsandquota.pl");
}

42
merge-group/merge-group.pl Executable file
View File

@@ -0,0 +1,42 @@
#! /usr/bin/perl
use strict;
use warnings;
if (scalar @ARGV < 1) {
die "Usage: $0 <lowest_gid>";
}
my $LOWEST_PVV_GID = int($ARGV[0]);
my @lines = ();
# Read old group file
open(IN, "/etc/group") || die "Unable to open /etc/group: $!";
while(<IN>) {
my @parts = split(":");
if ($parts[2] < $LOWEST_PVV_GID || $parts[0] eq "nogroup") {
push @lines, $_;
}
}
close IN || die "Unable to close /etc/group: $!";
# Read pvv group file
my $groupcount = 0;
open(PVV, "/etc/group.pvv") || die "Unable to open /etc/group.pvv: $!";
while(<PVV>) {
++$groupcount;
push @lines, $_;
}
close PVV || die "Unable to close /etc/group.pvv: $!";
if ($groupcount < 200) {
die "/etc/group.pvv has less than 200 groups, something went wrong";
}
open(OUT, ">/etc/group.tmp") || die "Unable to open /etc/group.tmp for writing: $!";
foreach (@lines) {
print OUT $_ || die "Can't write to /etc/group.tmp: $!";
}
close OUT || die "Unable to close /etc/group.tmp: $!";
rename "/etc/group.tmp", "/etc/group" || die "Unable to move /etc/group.tmp to /etc/group: $!";

87
merge-passwd/merge-passwd.pl Executable file
View File

@@ -0,0 +1,87 @@
#! /usr/bin/perl
use strict;
use warnings;
if (scalar @ARGV < 1) {
die "Usage: $0 <lowest_uid>";
}
my $LOWEST_PVV_UID = int($ARGV[0]);
my @passwd = ();
my %passwd_idx = ();
my %shadow = ();
my %filter = (
"nobody" => 1,
"news" => 1,
);
my $seen_nobody = 0;
open(PASSWD_IN, "/etc/passwd") || die "Unable to open /etc/passwd: $!";
while(<PASSWD_IN>) {
my @parts = split(":");
if ($parts[2] ne '' && $parts[2] < $LOWEST_PVV_UID || defined $filter{$parts[0]} && $filter{$parts[0]} == 1) {
push @passwd, $_;
$passwd_idx{$parts[0]} = $#passwd;
}
if (defined $filter{$parts[0]} && $filter{$parts[0]} == 1) {
$filter{$parts[0]}++;
}
}
close PASSWD_IN || die "Unable to close /etc/passwd: $!";
open(SHADOW_IN, "/etc/shadow") || die "Unable to open /etc/shadow: $!";
while(<SHADOW_IN>) {
my @parts = split(":");
if (defined $passwd_idx{$parts[0]}) {
$shadow{$parts[0]} = $_;
}
}
close SHADOW_IN || die "Unable to close /etc/shadow: $!";
open(PVV, "/etc/passwd.pvv") || die "Unable to open /etc/passwd.pvv: $!";
my $usercount = 0;
while(<PVV>) {
++$usercount;
my @parts = split(":");
my $user = $parts[0];
my $hash = $parts[1];
$parts[1] = "x";
push @passwd, join(":", @parts);
$passwd_idx{$parts[0]} = $#passwd;
$shadow{$parts[0]} = "$user:$hash:13777:0:99999:7:::\n";
}
close PVV || die "Unable to close /etc/passwd.pvv: $!";
if ($usercount < 1500) {
die "/etc/passwd.pvv has less than 1500 users, something went wrong";
}
# Passwd skal være world readable
umask 022;
open(PASSWD, ">/etc/passwd.tmp") || die "Unable to open /etc/passwd.tmp for writing: $!";
foreach (@passwd) {
print PASSWD $_ || die "Can't write to /etc/passwd.tmp: $!";
}
close PASSWD || die "Unable to close /etc/passwd.tmp: $!";
# Shadow skal IKKE være world readable
umask 027;
open(SHADOW, ">/etc/shadow.tmp") || die "Unable to open /etc/shadow.tmp for writing: $!";
foreach (keys %passwd_idx) {
if (exists($shadow{$_})) {
print SHADOW $shadow{$_};
} else {
print SHADOW "$_:*:12849:0:99999:7:::\n";
}
}
close SHADOW || die "Unable to close /etc/shadow.tmp: $!";
# Chown shadowfilen til root:Debian-exim
chown 0, scalar getgrnam("shadow"), "/etc/shadow.tmp";
rename "/etc/passwd.tmp", "/etc/passwd" || die "Unable to move /etc/passwd.tmp to /etc/passwd: $!";
rename "/etc/shadow.tmp", "/etc/shadow" || die "Unable to move /etc/shadow.tmp to /etc/shadow: $!";

13
msgsh/msgsh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/sh
if [ -f $HOME/.msgsh ]; then
cat $HOME/.msgsh
else
cat <<!
Brukeren din på PVV er sperret. Ta kontakt med styret.
Enten pr. e-mail til pvv@pvv.ntnu.no eller kom innom.
!
fi
sleep 5

210
new-user/nybruker.pl Executable file
View File

@@ -0,0 +1,210 @@
#! /usr/bin/perl
use strict;
use warnings;
use Term::ReadLine; # Sørg for at libterm-readline-gnu-perl er installert!
use FindBin;
##
## KONSTANTER
##
my $batchmode = 0; # Hvis true, ikke still spørsmål om autodetekterte variabler
my $homepath = "/home/pvv/d";
my $gitrepos = "root\@localhost:/local/adm/git/pillar.git";
my $mailtemplate = $FindBin::Bin . "/velkommenmail.template";
my $gitdir = $ENV{HOME}."/.nybruker-git";
my $passwd = "$gitdir/files/passwd/passwd.pvv";
##
## FELLES VARIABLER
##
our $term = new Term::ReadLine 'PVV Input';
##
## HOVEDPROGRAM
##
foreach my $option (@ARGV) {
$batchmode = 1 if $option eq "-b";
}
# Clone the repository
if (-e $gitdir) {
vsystem("rm", "-rf", $gitdir);
}
vsystem("git", "clone", $gitrepos, $gitdir);
# Det er viktig at passwrdfilen finnes
die "$passwd not found" unless -e $passwd;
my %ui = &getuserinfo($passwd);
# Sjekk at uid/gid er definert
&checkuserdata(%ui);
&createprincipal(%ui);
&makeuser($passwd, "$ui{name}:*K*:$ui{uid}:$ui{gid}:$ui{gecos}:" .
"$ui{dir}:$ui{shell}");
&sendmail($gitdir, $mailtemplate, %ui);
chdir($gitdir);
vsystem("git", "commit", "-a", "-m", "Adding user $ui{gecos} <$ui{name}\@pvv.ntnu.no>");
vsystem("git", "push");
print <<EOF;
Bruker er opprettet og lagt til i salt.
Husk å også legge brukeren til i mdboh:
ssh postgres.pvv.ntnu.no
su -
su - pvv
mdboh ny $ui{name} "$ui{gecos}"
Når du er ferdig med å opprette brukere, logg inn på et par maskiner og kjør salt:
salt-call state.highstate
EOF
exit(0);
##
## SUBRUTINER
##
sub sendmail {
my ($gitdir, $mailtemplate, %ui) = @_;
my $tmpfile = "/tmp/nybruker.$$";
&vsystem("m4 -DUSERNAME=$ui{name} " .
"-DEMAIL=$ui{email} " .
"$mailtemplate > $tmpfile");
my $editor = &ask("Editor (brukes kun for aa redigere epost som sendes)", $ENV{EDITOR} || "vim") unless $batchmode;
vsystem($editor, $tmpfile) unless $batchmode;
my $confirm = "yes";
$confirm = &ask("Send?", $confirm) unless $batchmode;
return unless ($confirm =~ m/^[yY]/);
vsystem("/usr/sbin/sendmail " . $ui{email} . " < $tmpfile");
vsystem("rm", $tmpfile);
}
sub vsystem {
my $rc;
do {
print(join(" ", map { $a = /\s/ ? "'$_'" : $_ } @_), "\n");
system(@_);
$rc = $?;
if ($rc) {
$rc = &ask("Systemkall feilet, prøv igjen?", "ja") !~ /n/i;
}
} while ($rc); # Repeat until successful
}
sub makeuser {
my ($passwd, $pwline) = @_;
open (my $passwd_fd, ">>", $passwd) or die "Unable to open $passwd: $!";
print $passwd_fd "$pwline\n";
close $passwd_fd;
}
sub getuserinfo {
my ($passwd) = @_;
my %ui;
for(my $i = 0; $i < $#ARGV; $i++) {
if ($ARGV[$i] eq "-n") {
$ui{name} = $ARGV[$i + 1];
$i++;
} elsif ($ARGV[$i] eq "-u") {
$ui{uid} = $ARGV[$i + 1];
$i++;
} elsif ($ARGV[$i] eq "-g") {
$ui{gid} = $ARGV[$i + 1];
$i++;
} elsif ($ARGV[$i] eq "-d") {
$ui{dir} = $ARGV[$i + 1];
$i++;
} elsif ($ARGV[$i] eq "-s") {
$ui{shell} = $ARGV[$i + 1];
$i++;
} elsif ($ARGV[$i] eq "-e") {
$ui{email} = $ARGV[$i + 1];
$i++;
}
}
my %users;
my %uids;
open (my $passwd_fd, $passwd) or die "Unable to open $passwd: $!";
while (<$passwd_fd>) {
chomp;
my ($user, undef, $uid, $gid) = split(":");
$users{$user} = $_;
$uids{$uid} = $_;
}
$ui{name} = &ask("User name", $ui{name}) unless ($ui{name} && $batchmode);
die "Brukernavn $ui{name} finnes allerede!\n" if exists $users{$ui{name}};
# my $pwent = `grep '^$ui{name}\:' /local/pwdist/passwd`;
my $pwent_str = `/usr/bin/python3 $ENV{'HOME'}/salt/standard/passwd/ask_stud_ldap.py $ui{name}`;
chomp($pwent_str);
my @pwent = split(":", $pwent_str);
if (scalar @pwent >= 5) {
$ui{uid} = $pwent[2] unless $ui{uid};
$ui{gid} = $pwent[3] unless $ui{gid};
$ui{gecos} = $pwent[4] unless $ui{gecos};
} else {
# Bruker finnes ikke i passordfilen, og er altså litt sær.
# Da er det nok best vi spør om alt.
$batchmode = 0;
}
$ui{uid} = &ask("UID", $ui{uid}) unless ($ui{uid} && $batchmode);
die "UID $ui{uid} finnes allerede!" if exists $uids{$ui{uid}};
$ui{gid} = &ask("GID, should be 13401", $ui{gid}) unless ($ui{gid} && $batchmode);
$ui{gecos} = &ask("Full name", $ui{gecos}) unless ($ui{gecos} && $batchmode);
$ui{dir} = $homepath . "/" . $ui{name} unless $ui{dir};
$ui{dir} = &ask("Home, should be /home/pvv/d/$ui{name}", $ui{dir}) unless ($batchmode);
$ui{email} = $ui{name} . '@stud.ntnu.no' unless $ui{email};
$ui{email} = &ask("E-mail", $ui{email}) unless ($batchmode);
$ui{shell} = "/bin/bash" unless $ui{shell};
$ui{shell} = &ask("Shell, should be /bin/bash", $ui{shell}) unless ($ui{shell} && $batchmode);
return %ui;
}
sub ask {
my ($prompt, $default) = @_;
return $term->readline($prompt . ": ", $default);
}
sub checkuserdata {
my (%ui) = @_;
if ($ui{uid} eq "") {
die "UID er ikkje definert\n";
}
if ($ui{gid} eq "") {
die "GID er ikkje definert\n";
}
}
sub createprincipal {
my %ui = @_;
my $adminprincipal = &ask( 'Admin principal' , $ENV{LOGNAME} . "/admin" ) unless $batchmode;
if ($adminprincipal ne '' ){
vsystem("kadmin -p $adminprincipal add $ui{name}");
}
return;
}

View File

View File

@@ -0,0 +1,14 @@
#! /bin/sh
# Run salt-call state.highstate, logging to /var/log/salt/nightly-highstate.
# If there is an error, we cat the entire file to stdout, so cron will complain
# to the admin.
export PATH=/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin
salt-call state.highstate --retcode-passthrough saltenv=base pillarenv=base > /var/log/salt/nightly-highstate 2>&1
RET=$?
if [ $RET -ne 0 ] || grep '^Failed:[[:space:]]*[1-9][0-9]*$' /var/log/salt/nightly-highstate >/dev/null 2>&1; then
cat /var/log/salt/nightly-highstate
fi
exit $RET

View File

@@ -0,0 +1,74 @@
#! /usr/bin/perl
use warnings;
use strict;
use Quota;
use Mail::Mailer;
use POSIX qw(strftime);
use Sys::Syslog qw(:standard :macros);
openlog("pvv-warnmailquota", "", LOG_LOCAL0);
open(USERS, "/etc/passwd.pvv") or die "Unable to open /etc/passwd.pvv: $!";
my @users = <USERS> or die "Unable to read from /etc/passwd.pvv: $!";
close USERS;
chomp @users;
my $mailer = new Mail::Mailer;
foreach my $line (@users) {
my ($uname,$pass,$uid,$gid,$gcos,$home,$shell) = split(/:/,$line) or next;
next if ($shell eq "/bin/msgsh");
next if ($shell eq "/bin/false");
next if ($home !~ /^\/home\/pvv/);
if (! -d $home) {
print "$uname ($uid:$gid) missing $home ($shell)\n";
next;
}
my ($block_curr, $block_soft, $block_hard, $block_timelimit, $inode_curr, $inode_soft, $inode_hard, $inode_timelimit) = Quota::query(Quota::getqcarg($home),$uid);
next if (! $block_soft || ! $block_curr);
next if ($block_curr < $block_soft);
# Kan ikke sende mail likevel...
next if (($block_curr + 16) >= $block_hard);
next if ($block_timelimit < time());
# next if (($uname ne "kvadrat") && ($uname ne "knuta") && ($uname ne "thorvan") && ($uname ne "oyving"));
my $forbruk = sprintf("%.1f", $block_curr * 100.0 / $block_soft);
my $timelimit = strftime("%Y-%m-%d %H:%M",localtime($block_timelimit));
my %headers;
$headers{'From'} = "Kvotesystem <drift\@pvv.ntnu.no>";
$headers{'To'} = "$uname\@pvv.ntnu.no";
$headers{'Subject'} = "PVV kvotebruk ${forbruk}% ($uname)";
$headers{'Content-Type'} = 'text/plain; charset=UTF-8';
$mailer->open(\%headers);
print $mailer qq{
Du har brukt opp ${forbruk}% av kvoten din på PVV. Hvis du
ikke er under kvota $timelimit, vil du miste muligheten
til å opprette og skrive til filer på PVV frem til du
sletter nok filer til at du er under kvoten igjen. Å miste
skrivetilgang medfører blandt annet at du ikke kan motta
mer epost, så vi anbefaler deg å rette på situasjonen
så snart som mulig.
Dette er en gyllen anledning til å kjøpe mer disk på PVV.
Disk koster NOK 32 per GiB, og minstekjøp er 6 GiB (NOK 192).
Se på http://www.pvv.ntnu.no/disk/ for mer detaljer.
For å se hvor mye kvote du har brukt, bruk kommandoen
"uquota" når du er logget inn. Ikke alle maskiner støtter denne
kommandoen, men den fungerer ihvertfall fra microbel.
};
#Hvis du ikke er under kvoten innen $timelimit
#vil du miste skrivetilgang til katalogen, som blandt
#annet vil forhindre leveranse av ny mail.
$mailer->close();
syslog("info", "%s mailed", $uname);
}
closelog();

16
sperret/sperret Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
cat <<!
Kontoen din er sperret som følge av mistanke om at passordet kan ha
kommet på avveie.
Ta kontakt med drift <drift@pvv.ntnu.no> for å få satt nytt passord og
få kontoen gjenåpnet.
2003-01-24
drift@pvv.ntnu.no
!
sleep 15

View File

@@ -0,0 +1,32 @@
#! /bin/sh
LOG=/var/log/pvvpakke.log
silentrun () {
if ! "$@" >>"$LOG" 2>&1; then
cat "$LOG"
exit 1;
fi
}
#Trunker loggen
echo -n > "$LOG"
if [ `uname` = FreeBSD ]; then
silentrun pkg update -q
silentrun pkg upgrade -q -y
silentrun pkg clean -q -y
elif [ -f /etc/debian_version ]; then
export DEBIAN_FRONTEND=noninteractive
silentrun /usr/bin/apt-get -q -q update
silentrun /usr/bin/apt-get --force-yes -q -q -s upgrade
silentrun /usr/bin/apt-get --force-yes -q -q upgrade
silentrun /usr/bin/apt-get clean
elif [ -f /etc/gentoo-release ]; then
true
# dette håndteres av 50emergesync.cron og 51glsacheck.cron
else
echo "Fant ikke systemtype!"
hostname
uname -a
fi

106
update-quota/update-quota.pl Executable file
View File

@@ -0,0 +1,106 @@
#! /usr/bin/perl
# vim:et:sw=2:ts=2
use warnings;
use strict;
use Quota;
my $reload_nfs = 1;
if (scalar @ARGV > 0 && $ARGV[0] eq '--noreload') {
$reload_nfs = 0;
shift @ARGV; # remove option
}
# Default kvotefil er /local/quota/quota.txt, men man kan override ved
# å oppgi en som første argument
my $quotafile = $ARGV[0] ? $ARGV[0] : "/local/quota/quota.txt";
my $tmpquotafile = $ARGV[1] ? $ARGV[1] : "/local/quota/tempquota.txt";
my %users;
#tie %nis, 'Net::NIS', 'netgroup', 'pvv';
open(USERS, "/etc/passwd.pvv") or die "Unable to open /etc/passwd.pvv: $!";
while(<USERS>) {
chomp;
$users{(split(":"))[0]} = $_;
}
my (%quota, %export);
open(QUOTA, $quotafile);
while(<QUOTA>) {
chomp;
s/#.*//;
s/\s*$//;
next if ($_ eq "");
my ($uname,$mb,$export)=split(/:/,$_);
$quota{$uname}=$mb;
$export{$uname}=$export;
}
close(QUOTA);
# Midlertidige kvoter (typisk under restoring av filer)
if (-e $tmpquotafile) {
open(TMPQUOTA, $tmpquotafile);
while(<TMPQUOTA>) {
chomp;
s/#.*//;
s/\s*$//;
next if ($_ eq "");
my ($until,$uname,$mb)=split(/:/,$_);
if ($until > time) {
$quota{$uname}=$mb;
}
}
close(TMPQUOTA);
}
open(DIRS, "/usr/bin/find /export/home/pvv -mindepth 1 -maxdepth 1 -type d|");
open(EXPORT, ">/etc/exports");
while(<DIRS>) {
chomp();
my $dir=$_;
next if ($dir =~ /lost\+found$/);
next if ($dir =~ /\/x$/);
next if ($dir =~ /\/x\//);
my $user = (reverse(split(/\//,$dir)))[0];
my @hosts = ("\@pvvhosts(no_subtree_check,rw,async)");
if ($export{$user}) {
push @hosts, map { "$_(rw,async)" } split(/[ ,]/,$export{$user});
}
my $hosts = join(" ", @hosts);
print EXPORT "$dir\t$hosts\n";
# print "$dir $user\n";
}
close(DIRS);
close(EXPORT);
$quota{'root'} = 0;
$quota{'nobody'} = 0;
# httpd er ikke i YP fordi den har samme UID som nobody der, men
# nobody har en annen UID i Ubuntu.
$users{'httpd'} = "httpd:*:60001:60001";
$quota{'httpd'} = 0;
my $dev=Quota::getqcarg("/export/home/pvv");
foreach my $uname (keys %users) {
my $quota=757;
my ($un,$pass,$uid,$gid) = split(/:/,$users{$uname}) or next;
if (defined($quota{$uname})) {
$quota+=$quota{$uname};
}
my $hardquota = $quota * 1.25;
if ($hardquota != 0 && $hardquota < 100) {
$hardquota = 100;
}
my ($block_curr, $block_soft, $block_hard) = Quota::query($dev, $uid);
if ($quota * 1024 != $block_soft || $hardquota * 1024 != $block_hard) {
print "Updating quota for $uname from ",($block_soft/1024)," MiB to $quota MiB\n";
Quota::setqlim($dev, $uid, $quota * 1024, $hardquota * 1024, 0, 0);
}
}
system("/etc/init.d/nfs-kernel-server reload") if $reload_nfs;

34
uquota/uquota.pl Executable file
View File

@@ -0,0 +1,34 @@
#! /usr/bin/perl
# Bare på nyere perl. Sukk.
# use warnings;
use strict;
use Quota;
use POSIX qw(strftime);
my ($name,$passwd,$uid,$gid, $quota,$comment,$gcos,$dir,$shell,$expire) = getpwuid($<);
my ($block_curr, $block_soft, $block_hard, $block_timelimit, $inode_curr, $inode_soft, $inode_hard, $inode_timelimit) = Quota::query(Quota::getqcarg($dir));
if (! $block_hard && ! $block_soft) {
print "Du har uendelig kvote.\n";
}
my $filled = sprintf("%.1f", $block_curr * 100.0 / $block_soft);
my $max = "(ingen maksimum)";
if ($block_hard) {
$max = sprintf("(max %.0f%%)",$block_hard * 100.0 / $block_soft);
}
my $mb_curr = int($block_curr / 1024);
my $mb_soft = int($block_soft / 1024);
my $days_timelimit = strftime("%Y-%m-%d %H:%M",localtime($block_timelimit));
print "Du har brukt ${mb_curr}MiB av ${mb_soft}MiB, eller ${filled}%.\n";
if ($block_timelimit) {
print "Du er over kvoten din ${max}, og etter $days_timelimit\n";
print "vil du miste skrivetilgang frem til du har slettet nok til å\n";
print "komme under 100% igjen.\n";
} else {
print "Du kan gå over kvoten din ${max} i opptil 7 dager.\n";
}