summaryrefslogtreecommitdiff
path: root/scripts/show-users.pl
blob: 8bd08252db638948cc8bb320907bce312b5050b2 (plain)
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
130
#! /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');
$cfg->{_active_dir_base} = '/opt/vyatta/config/active/';
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}};
}