Showing posts with label utmp. Show all posts
Showing posts with label utmp. Show all posts

Friday, February 8, 2008

Simple Linux Mods For Shell Script To Disable User Accounts

Hey there,

Yesterday, we posted a huge chunk of code getting the latest version our script to disable or delete user accounts. So, in the interest of keeping this page from becoming way too long, I'm just going to post the "diff" today. I quote the term diff, because I'm using it very loosely ;)

For the astute reader, I also noted a few missing single ticks on two lines in yesterday's script and have modified that post. Strangely enough, after repeated testing to make sure I was still all there, Solaris Unix doesn't seem to care (???) RedHat Linux picked it up right away though!

The modifications necessary to make the manual part of this version of our user disabling/deleting shell script are actually quite refreshing. While Solaris still insists that you unpack the utmp struct in /var/adm/wtmpx in order to get any year information from login monitoring commands, Linux provides this information for you with the "lastlog" command.

Yes, the modification is really that simple :)

So, without further ado, I've laid out the chunks of old code from yesterday, followed by the uncommented code that you should replace it with when running this on Linux. I put the two different places you'll need to make a change, in order, from top to bottom, as that seems normal to me ;)

You'll notice that the script's output is slightly different (and actually more conversational in tone), but, for our purposes, it doesn't need to be modified. We're still at the stage where we want to do a visual double-check.

Enjoy,


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

*** This section was in yesterday's script, but I've
*** changed the RedHat variable to be the lastlog
*** program instead of the /var/log/wtmp file

# $wtmpx_file_loc = "/var/adm/wtmpx"; # For Solaris
$wtmpx_file_loc = "/usr/bin/lastlog"; # For RedHat

*** The only other difference is a big chunk of code, but
*** actually a much simpler solution to implement in Linux

*** The Old Solaris Code - You should delete, or comment
* out this entire section and replace it with the new
* code below on Linux systems
*
* $template = "A32 A4 A32 l s s2 x2 l2 l x20 s A257 x";
* $recordsize = length(pack($template,( )));
* open(WTMP,$wtmpx_file_loc) or die "Unable to open wtmpx:$!\n";
* while (read(WTMP,$record,$recordsize)) {
* if ( $wtmpx_counter == 1 ) {
* print ".";
* $wtmpx_counter = 500;
* $wtmpx_total++;
* }
* ($ut_user,$ut_id,$ut_line,$ut_pid,$ut_type,$ut_e_termination,
* $ut_e_exit,$tv_sec,$tv_usec,$ut_session,$ut_syslen,$ut_host)=
* unpack($template,$record);
* push (@wtmpx_uv, "$ut_user ".scalar localtime($tv_sec));
* $wtmpx_counter--;
* $wtmpx_total++;
* }
*
*** End of the old Solaris code you should comment out or delete

* The substitute code for your Linux Shell Script
*
open(WTMP, "lastlog|") or die "can't open $wtmpx_file_loc: $!";
@rhwtmp = <WTMP>;
close(WTMP);
foreach $rhwtmp (@rhwtmp) {
if ( $wtmpx_counter == 1 ) {
print ".";
$wtmpx_counter = 500;
$wtmpx_total++;
}
push (@wtmpx_uv, $rhwtmp);
$wtmpx_counter--;
$wtmpx_total++;
}
*
* End of the substitute code - a lot easier to understand.


, Mike




Thursday, December 6, 2007

Taking a Look Inside Solaris' wtmpx

This is a Bonus Post, for those admins among us who aren't satisfied with the kind of information you can get from Solaris' standard commands that use /var/adm/wtmpx (like "last"). This is in line with the script we're also building up, in this post, to try and determine whether or not users have logged in within an arbitrary period of time and automatically lock up accounts and/or delete them completely based on that information.

I think this is still one post per day; so why am I calling it a Bonus Post? Partially because it was the first thing that came into my mind when I was trying to describe this blog-post and partially because the Perl scriplet that we're going to look at today is made up of constructs and functions that are what they are, and nothing more. I checked around and saw that there are variations on this script on other sites; mostly because there's only one un-convoluted way to do it (Even the argument to pack can't vary when tearing open the wtmpx structure(A32 A4 A32 l s s2 x2 l2 l x20 s A257 x). For that reason, I can only take credit for slapping together these predefined functions in a way that's slightly different than most. Some of it's in the coding and some of it's in what I'm trying to get out of the /var/adm/wtmpx file (nobody else seems to want it). This process is so rigid, I can no more take credit for it than I could take credit for inventing the "while loop" ;)

What we're looking for here is the "year." Yes, the "year." It's one of those things that I've never been able to figure out: Why was it left out of the "last" command? Great confusion can come of trying to pull auditing information and only knowing the months and dates people logged on. The "year" just seems like it should be included by default. I have no answer as to why it's not, but I do have a way for you to get it. Except for the initial command line, I've left out the error checking to save on space.

Note that the parts of the unpacked /var/adm/wtmpx are all the same, as well. We can change the names of the variables, but when you get right down to it, the file is composed of parts, and those parts are parts of a predefined structure. Note that in the below script, I'm looking for a user name and a year, like so:

$wtmpx_username holds the user name variable( I tried to name my variables in this script so that I would be reminded of what they represent later, when I've long since forgotten). Note that if we were coding this in "c" and accessing the actual utmp struct it would be a lot more work to make the variable names more easily memorable. The great thing about Perl is that it mimics the "c" behaviour but is actually only passing you an array of individual variables, so you can call them whatever you want.

$wtmpx_seconds holds the number of seconds since the epoch at which the login occurred. We pass that number to the Perl localtime() function, and it, in turn, can be parsed out to provide the "year!" If you want to read more about using the localtime() function in a script, check out this previous post.

That being said, you can find lots of different things inside /var/adm/wtmpx, like $wtmpx_line_device (usually the tty/pty), which can be compared against the string "system boot" to figure out every time your system has been rebooted. Of course, for the most part, the "last" command, and it's companions, get you all the information you really need. But it's nice to know you can get more specific data if you want it :)

Below; the Bonus Post Perl scriplet, and a promise to dive into understanding the pack and unpack functions in a future post!


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/usr/bin/perl

#
# 2007 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

if ( $#ARGV != 0 ) {
print "Usage: $0 accountName\n";
exit(1);

$account_name = $ARGV[0];
$recordsize = length(pack("A32 A4 A32 l s s2 x2 l2 l x20 s A257 x",( )));

open(WTMPX,"/var/adm/wtmpx");
while (read(WTMPX,$record,$recordsize)) {
($wtmpx_username,$wtmpx_userid,$wtmpx_line_device,$wtmpx_process_id,$wtmpx_type,$wtmpx_termination_status,$wtmpx_exit_status,$wtmpx_seconds,$wtmpx_useconds,$wtmpx_session,$wtmpx_syslen,$wtmpx_hostname) = unpack($template,$record);
if ($wtmpx_username eq "$account_name"){
print "$account_name ".scalar localtime($wtmpx_seconds)."\n";
}
}


, Mike