reddragdiva: (Default)
[personal profile] reddragdiva

The fun part of shell scripting is writing apparently perfectly Wirth-friendly code of immaculate Algol-like structure, peppered with inline bits of line noise that do the actual work. This is management-friendly because then they think they understand the immaculate structure, and because they don't understand the line noise it must therefore be simple.

#!/usr/bin/ksh
# Script XXXX_passwd_over_57_days_old
#
# D. Gerard   | 10-Jan-06   | Adapted from XXXXXXXXX version (oracle password)
#             |             | for XXXX (Unix password). Is there a Solaris
#             |             | command which just gives us this info? Should be.


# function days_since_epoch()
# Number of days since 1st January, 1970 (= day 0)
# adapted from from SysAdmin Magazine, July 2003:
# http://www.samag.com/documents/s=8284/sam0307b/0307b_l3.htm
# arguments: $1 = day, $2 = month, $3 = year in format YYYY
days_since_epoch()
{
typeset -i DSE

DSE=$((($1-32075+1461*($3+4800+($2-14)/12)/4+367*($2-2-($2-14)/12*12)/12-3*(($3+4900+($2-14)/12)/100)/4)-2440588))
echo $DSE
}

# Output file of names for deletion
LISTFILE=/tmp/oldlist
echo > $LISTFILE

# Today in days since 01 01 1970
TODAY= `days_since_epoch \`date +"%d %m 20%y"\``

# Get list of usernames from /etc/passwd. We only want those in the form aa99999
for i in `/usr/bin/awk -F:  '{print $1}' /etc/passwd | /usr/bin/grep '^[a-z]\{2\}[0-9]\{5\}$' `
do

# Get date of last password change (mmddyy, which we shuffle to yymmdd)
# NOTE: If never changed, logins gives the date as "010170"
# PS means password set; NP means no password set.
# NP will typically never have been used and have change date "010170"
DATE=`/usr/bin/logins -x -l $i | /usr/bin/awk '/PS|NP/  {print  substr($2,5,2) substr($2,1,4)}'`

# Solaris two year dates 69-99 are 1969-1999, dates 00-68 are 2000-2068
if [[ "690000" > $DATE ]]
        then DATE=`printf "20%s" $DATE`
        else DATE=`printf "19%s" $DATE`
fi

# Is $DATE more than 57 days before today? Add to list
if  [[ $(( $TODAY - `days_since_epoch \`(echo $DATE|/usr/bin/awk '{print substr($1,7,2) " " substr ($1,5,2) " " substr ($1,1,4)}')\``)) -gt 57 ]]
        then echo $i >> $LISTFILE
fi

done

# In future, we may take action on the list automatically.
exit 0

Note I've missed my chance to inline even more of the magic. The YY to YYYY conversion can be inlined with nawk and ?: and the script is less than polished in general. But that can be fixed next version. In fact, I'll see if I can get everything from logins on inside the final if.

(no subject)

Date: 2006-01-16 02:36 pm (UTC)
From: [identity profile] lpetersson.livejournal.com
Or one could consider it a pleasant way of commenting ones coding...

(no subject)

Date: 2006-01-16 02:49 pm (UTC)
vatine: Generated with some CL code and a hand-designed blackletter font (Default)
From: [personal profile] vatine
Would it make sense just getting time_ty and divide by 86400 (rounding left as an exercise for the wary), to get the relevant days-since-epoch? Just wondering, here...

(no subject)

Date: 2006-01-16 03:42 pm (UTC)
vatine: Generated with some CL code and a hand-designed blackletter font (Default)
From: [personal profile] vatine
date(1) format strings? I thought it could emit time-as-seconds-since epoch (but that might well be a GNU date-ism).

(no subject)

Date: 2006-01-16 03:16 pm (UTC)
ext_3375: Banded Tussock (Default)
From: [identity profile] hairyears.livejournal.com


The simple tricks are the deadliest. Use lots of whitespace: partly to provide a more readable layout; partly to cover the fact that someone's indented an interesting statement by eighty characters, pushing it offscreen and rendering it invisible to all but the most paranoid hackers.

(no subject)

Date: 2006-01-16 03:34 pm (UTC)
From: [identity profile] lpetersson.livejournal.com
rendering it invisible to all but the most paranoid hackers

And those who occassionally use the wordwrap function to check for such underhand ruses :)

(no subject)

Date: 2006-01-16 03:29 pm (UTC)
From: [identity profile] ciphergoth.livejournal.com
Why not use a real programming language for these jobs?

(no subject)

Date: 2006-01-16 05:08 pm (UTC)
From: [identity profile] sweh.livejournal.com
perl runs scripts :-)

(no subject)

Date: 2006-01-16 03:31 pm (UTC)
From: [identity profile] oscarhocklee.livejournal.com
Hmm. Is the Korn shell there ksh88 or ksh93? If the latter, you can rewrite the entire thing in pure shell... if the former, everything but the call to 'date' :-)

(no subject)

Date: 2006-01-16 05:33 pm (UTC)
From: [identity profile] sweh.livejournal.com
Whilst ksh is good, sometimes it's quicker to call external programs like grep and awk. And I say this as a ksh88 programmer of 15 years :-)

(no subject)

Date: 2006-01-16 05:54 pm (UTC)
From: [identity profile] oscarhocklee.livejournal.com
Yes, but sometimes (quite often) it isn't :-)

(no subject)

Date: 2006-01-16 05:31 pm (UTC)
From: [identity profile] sweh.livejournal.com
You can avoid the whole DSE thing by calculating the YYYYMMDD date corresponding to 57 days ago, and just compare the output of "logins" to that.

Also, just do the whole
for i in
do
done >> $LISTFILE

and so avoid do the append inside the loop.

Of course, since you read /etc/passwd directly to get the list of usernames, you don't appear to care about other naming services other than "files", so just read the /etc/shadow file directly,
which has the DSE value (or blank)

#!/bin/ksh -p

LISTFILE=/tmp/oldlist

days_since_epoch()
{
  typeset -i DSE

  DSE=$((($1-32075+1461*($3+4800+($2-14)/12)/4+367*($2-2-($2-14)/12*12)/12-3*(($3+4900+($2-14)/12)/100)/4)-2440588))
  echo $DSE
}

d=$(days_since_epoch $(date +"%d %m %Y"))
let d=d-57
awk -F: '$3 < '$d' { print $1}' /etc/shadow | grep '^[a-z]\{2\}[0-9]\{5\}$' > $LISTFILE

(note the %Y - this gives YYYY and is in Solaris 8 onwards)

March 2022

S M T W T F S
  12 345
6789101112
13141516171819
20212223242526
2728293031  

Style Credit

Expand Cut Tags

No cut tags