#! /usr/bin/perl # **** License **** # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # This code was originally developed by Vyatta, Inc. # Portions created by Vyatta are Copyright (C) 2007 Vyatta, Inc. # All Rights Reserved. # # Author: Stephen Hemminger # Date: Sept 2009 # Description: Show password accounts # # **** End License **** use lib "/opt/vyatta/share/perl5"; use Vyatta::Config; use IO::Seekable; use strict; use warnings; sub usage { print "Usage: $0 {type}\n"; print " type := all | vyatta | locked | other | color\n"; exit 1; } use constant { VYATTA => 0x1, OTHER => 0x2, LOCKED => 0x4, }; my %filters = ( 'vyatta' => VYATTA, 'other' => OTHER, 'locked' => OTHER|LOCKED, 'all' => VYATTA|OTHER|LOCKED, ); my $filter = 0; for (@ARGV) { my $mask = $filters{$_}; unless ($mask) { warn "Unknown type $_\n"; usage(); } $filter |= $mask; } # Default is everything but locked accounts $filter |= VYATTA|OTHER if ($filter == 0); # Read list of Vyatta users my $cfg = new Vyatta::Config; $cfg->setLevel('system login user'); my %vuser = map { $_ => 1 } $cfg->listOrigNodes(); # Setup to access lastlog open (my $lastlog, '<', "/var/log/lastlog") or die "can't open /var/log/lastlog:$!"; # Magic values based on binary format of last log # See /usr/include/bits/utm.h my $typedef = 'L Z32 Z256'; my $reclen = length(pack($typedef)); sub lastlog { my $uid = shift; sysseek($lastlog, $uid * $reclen, SEEK_SET) or die "seek failed: $!"; my ($rec, $line, $host, $time); if (sysread($lastlog, $rec, $reclen) == $reclen) { my ($time, $line, $host) = unpack($typedef, $rec); return scalar(localtime($time)), $line, $host if ($time != 0); } return ("never logged in", "", ""); } # Walk password file # Note: this only works as root my %users; setpwent(); while ( my ($u, $p, $uid) = getpwent()) { my $l = length($p); my $status; my $flag = 0; my $type = defined($vuser{$u}) ? 'vyatta' : 'other'; if ($type eq 'vyatta') { $flag |= VYATTA; } elsif ($l != 1) { $flag |= OTHER; } # only works as root, otherwise shadow file is inaccessible if ($l == 0) { $type .= '!'; } if ($l == 1) { $flag |= LOCKED; $type .= '-'; } next if (($flag & $filter) == 0); my ($time, $line, $host) = lastlog($uid); # fields to printf $users{$u} = [ $type, $line, $host, $time ]; } endpwent(); close $lastlog; my $fmt = "%-15s %-7s %-8s %-19s %s\n"; printf $fmt, "Username","Type","Tty", "From","Last login"; foreach my $u (sort keys %users) { printf $fmt, $u, @{$users{$u}}; }