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
|
#! /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}};
}
|