1# linux-lib.pl 2# Functions for reading linux format last output 3 4# passfiles_type() 5# Returns 0 for old-style passwords (/etc/passwd only), 1 for FreeBSD-style 6# (/etc/master.passwd) and 2 for SysV (/etc/passwd & /etc/shadow) 7sub passfiles_type 8{ 9return &password_file($config{'shadow_file'}) ? 2 : 0; 10} 11 12# groupfiles_type() 13# Returns 0 for normal group file (/etc/group only) and 2 for shadowed 14# (/etc/group and /etc/gshadow) 15sub groupfiles_type 16{ 17return &password_file($config{'gshadow_file'}) ? 2 : 0; 18} 19 20# open_last_command(handle, user) 21sub open_last_command 22{ 23local ($fh, $user) = @_; 24local $quser = quotemeta($user); 25open($fh, "(last -F $quser || last $quser) |"); 26} 27 28# read_last_line(handle) 29# Parses a line of output from last into an array of 30# user, tty, host, login, logout, period 31sub read_last_line 32{ 33$fh = $_[0]; 34while(1) { 35 chop($line = <$fh>); 36 if (!$line) { return (); } 37 if ($line =~ /system boot/) { next; } 38 if ($line =~ /^(\S+)\s+(\S+)\s+(\S+)?\s+(\S+\s+\S+\s+\d+\s+\d+:\d+)\s+\-\s+(\S+)\s+\((\d+:\d+)\)/) { 39 # jcameron pts/0 fudu Thu Feb 22 09:47 - 10:15 40 return ($1, $2, $3, $4, $5 eq "down" ? "Shutdown" : $5, $6); 41 } 42 elsif ($line =~ /^(\S+)\s+(\S+)\s+(\S+)?\s+(\S+\s+\S+\s+\d+\s+\d+:\d+:\d+\s+\d+)\s+\-\s+(\S+\s+\S+\s+\d+\s+\d+:\d+:\d+\s+\d+)\s+\((\d+:\d+)\)/) { 43 # jcameron pts/0 fudu Thu Feb 22 09:47 - 10:15 44 return ($1, $2, $3, $4, $5 eq "down" ? "Shutdown" : $5, $6); 45 } 46 elsif ($line =~ /^(\S+)\s+(\S+)\s+(\S+)?\s+(\S+\s+\S+\s+\d+\s+\d+:\d+)\s+still/) { 47 # root pts/0 fudu Fri Feb 23 18:46 still logged in 48 return ($1, $2, $3, $4); 49 } 50 } 51} 52 53# os_most_recent_logins() 54# Returns hash ref from username to the most recent login as time string 55sub os_most_recent_logins 56{ 57my %rv; 58&clean_language(); 59open(LASTLOG, "lastlog |"); 60while(<LASTLOG>) { 61 s/\r|\n//g; 62 if (/^(\S+)/) { 63 my $user = $1; 64 if (/((\S+)\s+(\S+)\s+\d+\s+(\d+):(\d+):(\d+)\s+([\-\+]\d+)\s+(\d+))/) { 65 # Have a date to parse 66 $rv{$user} = $1; 67 } 68 else { 69 $rv{$user} = undef; 70 } 71 } 72 } 73close(LASTLOG); 74&reset_environment(); 75return \%rv; 76} 77 78# logged_in_users() 79# Returns a list of hashes containing details of logged-in users 80sub logged_in_users 81{ 82local @rv; 83open(WHO, "who |"); 84while(<WHO>) { 85 if (/^(\S+)\s+(\S+)\s+(\S+\s+\d+\s+\d+:\d+)\s+(\((\S+)\))?/) { 86 push(@rv, { 'user' => $1, 'tty' => $2, 87 'when' => $3, 'from' => $5 }); 88 } 89 } 90close(WHO); 91return @rv; 92} 93 94# use_md5() 95# Returns 1 if pam is set up to use MD5 encryption, 2 for blowfish, 3 for SHA512 96sub use_md5 97{ 98if (defined($use_md5_cache)) { 99 # Don't re-look this up 100 return $use_md5_cache; 101 } 102local $md5 = 0; 103if (&foreign_check("pam")) { 104 # Use the PAM module if we can 105 &foreign_require("pam", "pam-lib.pl"); 106 local @conf = &foreign_call("pam", "get_pam_config"); 107 local ($svc) = grep { $_->{'name'} eq 'passwd' } @conf; 108 LOOP: 109 foreach my $m (@{$svc->{'mods'}}) { 110 if ($m->{'type'} eq 'password') { 111 if ($m->{'args'} =~ /md5/) { 112 $md5 = 1; 113 } 114 elsif ($m->{'args'} =~ /sha512/) { 115 $md5 = 3; 116 } 117 elsif ($m->{'args'} =~ /blowfish/) { 118 $md5 = 2; 119 } 120 elsif ($m->{'module'} =~ /pam_stack\.so/ && 121 $m->{'args'} =~ /service=(\S+)/) { 122 # Referred to another service! 123 ($svc) = grep { $_->{'name'} eq $1 } @conf; 124 if ($svc) { goto LOOP } 125 else { last; } 126 } 127 elsif ($m->{'control'} eq 'include') { 128 # Include another section 129 ($svc) = grep { $_->{'name'} eq $m->{'module'} } 130 @conf; 131 if ($svc) { goto LOOP } 132 else { last; } 133 } 134 } 135 elsif ($m->{'include'}) { 136 # Include another section, with @ syntax 137 ($svc) = grep { $_->{'name'} eq $m->{'include'} } @conf; 138 if ($svc) { goto LOOP } 139 else { last; } 140 } 141 } 142 } 143if (!$md5 && &open_readfile(PAM, "/etc/pam.d/passwd")) { 144 # Otherwise try to check the PAM file directly 145 while(<PAM>) { 146 s/#.*$//g; 147 if (/^password.*md5/) { $md5 = 1; } 148 elsif (/^password.*blowfish/) { $md5 = 2; } 149 elsif (/^password.*sha512/) { $md5 = 3; } 150 } 151 close(PAM); 152 } 153if (!$md5 && (&open_readfile(PAM, "/etc/pam.d/common-password") || 154 &open_readfile(PAM, "/etc/pam.d/system-auth"))) { 155 # Then try reading common password config file 156 while(<PAM>) { 157 s/#.*$//g; 158 if (/^password.*md5/) { $md5 = 1; } 159 elsif (/^password.*blowfish/) { $md5 = 2; } 160 elsif (/^password.*sha512/) { $md5 = 3; } 161 } 162 close(PAM); 163 } 164if (&open_readfile(DEFS, "/etc/login.defs")) { 165 # The login.defs file is used on debian sometimes 166 while(<DEFS>) { 167 s/#.*$//g; 168 $md5 = 1 if (/MD5_CRYPT_ENAB\s+yes/i); 169 } 170 close(DEFS); 171 } 172$use_md5_cache = $md5; 173return $md5; 174} 175 1761; 177