version 1.2, 2001/06/20 22:19:58 |
version 1.3, 2002/05/16 18:27:34 |
|
|
#!/usr/bin/perl -w |
#!/usr/bin/perl -w |
# |
# |
# Copyright (c) 1996, 2001 Todd C. Miller <Todd.Miller@courtesan.com> |
# Copyright (c) 1996, 2001, 2002 Todd C. Miller <Todd.Miller@courtesan.com> |
# All rights reserved. |
# All rights reserved. |
# |
# |
# Redistribution and use in source and binary forms, with or without |
# Redistribution and use in source and binary forms, with or without |
|
|
# $OpenBSD$ |
# $OpenBSD$ |
# |
# |
|
|
use File::Temp qw(:mktemp); |
use POSIX qw(S_ISREG); |
use Fcntl qw(:DEFAULT :flock); |
use Fcntl qw(:DEFAULT :flock); |
use Time::Local; |
|
|
|
# Keep out the stupid |
# Keep out the stupid |
die "Only root may run $0.\n" if $>; |
die "Only root may run $0.\n" if $>; |
die "Usage: $0 [days]\n" if $#ARGV > 0; |
die "Usage: $0 [days]\n" if $#ARGV > 0; |
|
|
# Pathnames |
# Pathnames |
$keyfile = '/etc/skeykeys'; |
$skeydir = '/etc/skey'; |
$template = "$keyfile.XXXXXXXX"; |
|
|
|
# Quick mapping of month name -> number |
|
%months = ('Jan', 0, 'Feb', 1, 'Mar', 2, 'Apr', 3, 'May', 4, 'Jun', 5, |
|
'Jul', 6, 'Aug', 7, 'Sep', 8, 'Oct', 9, 'Nov', 10, 'Dec', 11); |
|
|
|
# Remove entries that haven't been modified in this many days. |
# Remove entries that haven't been modified in this many days. |
$days_old = $ARGV[0] || -1; |
$days_old = $ARGV[0] || -1; |
|
|
# Safe umask |
# Safe umask |
umask(077); |
umask(077); |
|
|
# Open and lock the current key file |
# Current time |
open(OLD, $keyfile) || die "$0: Can't open $keyfile: $!\n"; |
$now = time(); |
flock(OLD, LOCK_EX) || die "$0: Can't lock $keyfile: $!\n"; |
|
|
|
# Safely open temp file |
# Slurp mode |
($NEW, $temp) = mkstemp($template); |
undef $/; |
die "$0: Can't open tempfile $template: $!\n" unless $temp; |
|
|
|
# Run at a high priority so we don't keep things locked for too long |
chdir($skeydir) || die "$0: Can't cd to $skeydir: $!\n"; |
setpriority(0, 0, -4); |
opendir(SKEYDIR, ".") || die "$0: Can't open $skeydir: $!\n"; |
|
while (defined($user = readdir(SKEYDIR))) { |
|
next if $user =~ /^\./; |
|
if (!sysopen(SKEY, $user, 0, O_RDWR | O_NONBLOCK | O_NOFOLLOW)) { |
|
warn "$0: Can't open $user: $!\n"; |
|
next; |
|
} |
|
if (!flock(SKEY, LOCK_EX)) { |
|
warn "$0: Can't lock $user: $!\n"; |
|
close(SKEY); |
|
next; |
|
} |
|
|
while (<OLD>) { |
if (!stat(SKEY)) { |
chomp(); |
warn "$0: Can't stat $user: $!\n"; |
|
close(SKEY); |
|
next; |
|
} |
|
|
# Valid entry: 'username hash seq seed key date" |
# Sanity checks. |
if ( /^[^\s#]+\s+(\S+\s+)?[0-9]+\s+[A-z0-9]+\s+[a-f0-9]+\s+(Jan|Feb|Mar|Apr|May|Ju[nl]|Aug|Sep|Oct|Nov|Dec)\s+[0-9]+,\s*[0-9]+\s+[0-9]+:[0-9]+:[0-9]+$/ ) { |
if (!S_ISREG((stat(_))[2])) { |
|
warn "$0: $user is not a regular file\n"; |
|
close(SKEY); |
|
next; |
|
} |
|
if (((stat(_))[2] & 07777) != 0600) { |
|
printf STDERR ("%s: Bad mode for %s: 0%o\n", $0, $user, |
|
(stat(_))[2]); |
|
close(SKEY); |
|
next; |
|
} |
|
if ((stat(_))[3] != 1) { |
|
printf STDERR ("%s: Bad link count for %s: %d\n", $0, $user, |
|
(stat(_))[3]); |
|
close(SKEY); |
|
next; |
|
} |
|
|
@entry = split(/[\s,:]+/, $_); |
# Remove zero size entries |
# Prune out old entries if asked to |
if (-z _) { |
if ($days_old > 0) { |
unlink($user) || warn "$0: Can't unlink $user: $!\n"; |
# build up time based on date string |
close(SKEY); |
$sec = $date[10]; |
next; |
$min = $date[9]; |
} |
$hours = $date[8]; |
|
$mday = $date[6] - 1; |
|
$mon = $months{$date[5]}; |
|
$year = $date[7] - 1900; |
|
|
|
$now = time(); |
# Prune out old entries if asked to |
$then = timelocal($sec,$min,$hours,$mday,$mon,$year); |
if ($days_old > 0) { |
if (($now - $then) / (60 * 60 * 24) - 1 > $days_old) { |
$then = (stat(_))[9]; |
next; # too old |
if (($now - $then) / (60 * 60 * 24) - 1 > $days_old) { |
} |
unlink($user) || warn "$0: Can't unlink $user: $!\n"; |
|
close(SKEY); |
|
next; |
} |
} |
|
} |
|
|
# Missing hash type? Must be md4... |
# Read in the entry and check its contents. |
if ($entry[1] =~ /^\d/) { |
$entry = <SKEY>; |
splice(@entry, 1, 0, "md4"); |
if ($entry !~ /^\S+[\r\n]+\S+[\r\n]+\d+[\r\n]+[A-z0-9]+[\r\n]+[a-f0-9]+[\r\n]+$/) { |
} |
warn "$0: Invalid entry for $user:\n$entry"; |
|
|
printf $NEW "%s %s %04d %-16s %s %4s %02d,%-4d %02d:%02d:%02d\n", |
|
$entry[0], $entry[1], $entry[2], $entry[3], $entry[4], |
|
$entry[5], $entry[6], $entry[7], $entry[8], $entry[9], |
|
$entry[10] || do { |
|
warn "Can't write to $temp: $!\n"; |
|
unlink($temp); |
|
exit(1); |
|
}; |
|
} |
} |
} |
|
close(OLD); |
|
close($NEW); |
|
|
|
# Set owner/group/mode on tempfile and move to real location. |
close(SKEY); |
($mode, $nlink, $uid, $gid) = (stat($keyfile))[2..5]; |
|
if (!defined($mode)) { |
|
unlink($temp); |
|
die "$0: Unable to stat $keyfile: $!\n"; |
|
} |
} |
if (!chmod($mode, $temp)) { |
|
unlink($temp); |
|
die "$0: Unable to set mode of $temp to $mode: $!\n"; |
|
} |
|
if (!chown($uid, $gid, $temp)) { |
|
unlink($temp); |
|
die "$0: Unable to set owner of $temp to ($uid, $gid): $!\n"; |
|
} |
|
if ($nlink != 1) { |
|
$nlink--; |
|
warn "$0: Old $keyfile had $nlink hard links, those will be broken\n"; |
|
} |
|
# Leave temp file in place if rename fails. Might help in debugging. |
|
rename($temp, $keyfile) || die "$0: Unable to rename $temp to $keyfile: $!\n"; |
|
|
|
exit(0); |
exit(0); |