a shell script for review.


 
Thread Tools Search this Thread
Top Forums Shell Programming and Scripting a shell script for review.
# 1  
Old 10-05-2009
Question a shell script for review.

I have written a bit of shell that lets our company check all our SSL certs.

the aim is to have a list of servers and run this check from cron once a week.

Our managers have decided that we will not run BASH, so it has been written in /bin/sh and only needs openssl, no perl, no bash, no extra packages.

I look foward to input / review / comments.
there is nothing better for learning that have someone show you why your code is bad...

if you can find use for it in your company then feel free to use it.

Code:
#!/bin/sh
######################################
#
# SSL testing tool.
#
# Derek Robson  03/10/2009
# used to test if an SSL cert is due to expire.
#  SSL_test.sh <server name>
#
#
######################################
#
# CONFIG SETTINGS
#
# Who to email if SSL cert is due 
EMAIL="bob@mycomany.com"

# how manys days before cert expires do we want to be alerted?
DAYS_WARNING=45

# Also email the cert owner?
MAIL_OWNER=NO

# if no SSL is running on server should we exit with what error code? 
NO_SSL=0;



date2unix() {
        # unix date from Gregorian calendar date
        # Since leap years add aday at the end of February, 
        # calculations are done from 1 March 0000 (a fictional year)
        d2j_tmpmonth=`expr 12 \* ${3} + ${1} - 3` 
        
        # If it is not yet March, the year is changed to the previous year
        d2j_tmpyear=`expr ${d2j_tmpmonth} / 12`
        
        # The number of days from 1 March 0000 is calculated
        # and the number of days from 1 Jan. 4713BC is added 
        d2j_tmpdays=`expr 734 \* ${d2j_tmpmonth} + 15`
 
        # this gives us the julian day number.
        d2j_JULIAN=`expr \( ${d2j_tmpdays} / 24 \) - \( 2 \* ${d2j_tmpyear} \) + \( ${d2j_tmpyear} / 4 \) - \( ${d2j_tmpyear} / 100 \) + \( ${d2j_tmpyear} / 400 \) + $2 + 1721119`

        # this convert julian day number to classic unix time number
        UNIX_date=`expr \( \( \( \( \( ${d2j_JULIAN} - 2440587 \) \* 24 \) + 12 + ${4} \) \* 60 \) + ${5} \) \* 60 `

        echo $UNIX_date 
}





GET_EXPIR_DATE() {
        #
        # get the SSL expire date from the web server.
        # returns a line like this "Not After : Nov 12 12:00:00 2011 GMT"
        # can be used on other port numbers by use of $2, assumes 443 if no $2 set.

        # what host are we checking?
        HOST=$1

        # What port number?
        PORT=443 
        
        # connect to server and get full SSL cert.
        FULL_SSL_BLOB=`echo "HEAD / HTTP/1.0\n Host: $1:443\n\n EOT\n" | openssl s_client -connect $1:443 2>&1`
        if [ $? -eq 0 ];then
        # cut out just the encoded SSL cert
        SSL_CERT=`echo "$FULL_SSL_BLOB" | sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' `

        # decode the SSL cert recover the "Not After" date      
        EXPIR_DATE=`echo "$SSL_CERT" | openssl x509 -noout -text -certopt no_signame 2>&1 | grep "Not After"  `
        
        echo $EXPIR_DATE
        else 
        echo "ERROR"
        fi 
}



GET_EXPIR_DATE_BUG() {
        #
        # get the SSL expire date from the web server and use works around an  SSL bug with some certs.
        # returns a line like this "Not After : Nov 12 12:00:00 2011 GMT"
        # can be used on other port numbers by use of $2, assumes 443 if no $2 set.

        # what host are we checking?
        HOST=$1

        # What port number?
        PORT=443 
 
        # connect to server and get full SSL cert.
        FULL_SSL_BLOB=`echo "HEAD / HTTP/1.0\n Host: $1:443\n\n EOT\n" | openssl s_client -prexit -connect $1:443 2>&1`
        if [ $? -eq 0 ];then
        # cut out just the encoded SSL cert
        SSL_CERT=`echo "$FULL_SSL_BLOB" | sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' `

        # decode the SSL cert recover the "Not After" date
        EXPIR_DATE=`echo "$SSL_CERT" | openssl x509 -noout -text -certopt no_signame 2>&1 | grep "Not After"  `
        
        echo $EXPIR_DATE
        else
        echo "ERROR"
        fi
}




GET_CERT_OWNER() {
        #
        # get the SSL owners email address from the web server.
        # returns an emial address
        # can be used on other port numbers by use of $2, assumes 443 if no $2 set.

        # what host are we checking?
        HOST=$1

        # What port number?
        PORT=443

        # connect to server and get full SSL cert.
        FULL_SSL_BLOB=`echo "HEAD / HTTP/1.0\n Host: $1:443\n\n EOT\n" | openssl s_client -prexit -connect $1:443 2>&1`

        # cut out just the encoded SSL cert
        SSL_CERT=`echo "$FULL_SSL_BLOB" | sed -n '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' `

        # decode the SSL cert recover the "Not After" date
        SSL_OWNER=`echo "$SSL_CERT" | openssl x509 -noout -text -certopt no_signame | grep "email" | sed -e 's/email://g'  `

        echo $SSL_OWNER
}




GET_MONTH() 
{
        # convert month name to number
    case ${1} in
        Jan) echo 1 ;;
        Feb) echo 2 ;;
        Mar) echo 3 ;;
        Apr) echo 4 ;;
        May) echo 5 ;;
        Jun) echo 6 ;;
        Jul) echo 7 ;;
        Aug) echo 8 ;;
        Sep) echo 9 ;;
        Oct) echo 10 ;;
        Nov) echo 11 ;;
        Dec) echo 12 ;;
          *) echo  0 ;;
    esac
}



#################### MAIN ###########################


         # setup with todays date/time
         NOW_YEAR=`date "+%Y"`
         NOW_MONTH=`date "+%m"`
         NOW_DAY=`date "+%d"`
         NOW_HOUR=`date "+%H"`
         NOW_MINUTE=`date "+%M"`

         # get the expire date of the SSL cert from server.
         BOB=`GET_EXPIR_DATE $1 $2`
         if [ "$BOB" = "" ];then
         # assume we need to use the SSL bug switch 
         BOB=`GET_EXPIR_DATE_BUG $1 $2`
         fi

         if [ "$BOB" = "ERROR" ];then
         exit $NO_SSL
         else         
         # take date from SSL cert and cut down to year, month, day, hour and minute
         SSL_YEAR=`echo $BOB | cut -f 7 -d " "`
         SSL_Month=`echo $BOB | cut -f 4 -d " "`
         # conver month from name to number         
         SSL_MONTH=`GET_MONTH $SSL_Month`
         SSL_DAY=`echo $BOB | cut -f 5 -d " "`
         SSL_HOUR=`echo $BOB | cut -f 6 -d " "| cut -f 1 -d ":"`
         SSL_MINUTE=`echo $BOB | cut -f 6 -d " "| cut -f 2 -d ":"`

         # convert both todays date and SSL cert dat to unix time.
         SSL_DATE=`date2unix $SSL_MONTH $SSL_DAY $SSL_YEAR $SSL_HOUR $SSL_MINUTE`
         NOW_DATE=`date2unix $NOW_MONTH $NOW_DAY $NOW_YEAR $NOW_HOUR $NOW_MINUTE`

         #calculate how many day to go until cert expires.
         DATE_DIFFRANCE=`expr $SSL_DATE - $NOW_DATE`
         DAY_DIFFRANCE=`expr $DATE_DIFFRANCE / 86400`

         # take action if needed.
         if [ $DAY_DIFFRANCE -lt $DAYS_WARNING ]; then

         OWNER=`GET_CERT_OWNER $1 $2`

         MESSG="The SSL certificate for $1 on port $2 will expire on $SSL_DAY/$SSL_MONTH/$SSL_YEAR\n\n"

         echo $MESSG | mailx -s "SSL cert due to expire" $EMAIL 

         if [ "$MAIL_OWNER" = "YES" ] ;then
         echo $MESSG | mailx -s "SSL cert due to expire" $OWNER
         fi

         else

         exit 0

         fi

         fi


Last edited by robsonde; 10-06-2009 at 12:57 AM..
# 2  
Old 10-06-2009
MySQL Nice

Nice approach to resolving the number of days; I have never seen it tackled that way.

I will play with it later.

Thanks for sharing it.
# 3  
Old 10-06-2009
Quote:
Originally Posted by steadyonabix
Nice approach to resolving the number of days; I have never seen it tackled that way.

I will play with it later.

Thanks for sharing it.
many date solutions use perl, which we did not want to use.
others use GNU date, which we don't have on many of our systems.

one possible problem is that this code is not time-zone aware yet, SSL dates are in GMT, the compare date is local system time.
this would only be an issue is you set the alert days to less than 2 or 3.

the code still needs error checking, input validation, usage notes, more comments, and some other clean-up...

this is just the first working version :-)

already we have found several SSL cert's that need re-issuing.
# 4  
Old 10-06-2009
Quote:
Originally Posted by robsonde
I have written a bit of shell that lets our company check all our SSL certs.

the aim is to have a list of servers and run this check from cron once a week.

Our managers have decided that we will not run BASH, so it has been written in /bin/sh and only needs openssl, no perl, no bash, no extra packages.

I look foward to input / review / comments.
there is nothing better for learning that have someone show you why your code is bad...

if you can find use for it in your company then feel free to use it.

Code:
#!/bin/sh

date2unix() {
        # unix date from Gregorian calendar date
        # Since leap years add aday at the end of February, 
        # calculations are done from 1 March 0000 (a fictional year)
        d2j_tmpmonth=`expr 12 \* ${3} + ${1} - 3` 
        
        # If it is not yet March, the year is changed to the previous year
        d2j_tmpyear=`expr ${d2j_tmpmonth} / 12`
        
        # The number of days from 1 March 0000 is calculated
        # and the number of days from 1 Jan. 4713BC is added 
        d2j_tmpdays=`expr 734 \* ${d2j_tmpmonth} + 15`
 
        # this gives us the julian day number.
        d2j_JULIAN=`expr \( ${d2j_tmpdays} / 24 \) - \( 2 \* ${d2j_tmpyear} \) + \( ${d2j_tmpyear} / 4 \) - \( ${d2j_tmpyear} / 100 \) + \( ${d2j_tmpyear} / 400 \) + $2 + 1721119`

        # this convert julian day number to classic unix time number
        UNIX_date=`expr \( \( \( \( \( ${d2j_JULIAN} - 2440587 \) \* 24 \) + 12 + ${4} \) \* 60 \) + ${5} \) \* 60 `

        echo $UNIX_date 
}


Why are you using expr? The standard Unix shell has arithmetic built in.

See the shell date functions at The Dating Game.
... ...
Quote:
Code:
         # setup with todays date/time
         NOW_YEAR=`date "+%Y"`
         NOW_MONTH=`date "+%m"`
         NOW_DAY=`date "+%d"`
         NOW_HOUR=`date "+%H"`
         NOW_MINUTE=`date "+%M"`


Calling date five times is inefficient and will fail if a time boundary is crossed between calls to date.

Code:
 eval "$( date +"NOW_YEAR=+%Y NOW_MONTH=%m NOW_DAY=+%d NOW_HOUR=%H NOW_MINUTE=%M)"

# 5  
Old 10-06-2009
I saw similar code somewhere and simplified (good for a few hundred years) it to (in bash):
Code:
(( ++mon < 4 )) && let year-=1 mon+=12
let j='year*1461/4+mon*153/5+day'
let s='(((j-719606)*24+hour)*60+min)*60+sec'

# 6  
Old 10-06-2009
Quote:
Originally Posted by binlib
I saw similar code somewhere and simplified (good for a few hundred years) it to (in bash):
Code:
(( ++mon < 4 )) && let year-=1 mon+=12
let j='year*1461/4+mon*153/5+day'
let s='(((j-719606)*24+hour)*60+min)*60+sec'


Translated to portable syntax that will run in any POSIX shell:

Code:
mon=$(( $mon + 1 ))
if [ $mon -lt 4 ]
then
   year=$(( $year - 1 ))
   mon=$(( mon + 12 ))
fi
j=$(( $year * 1461 / 4 + mon * 153 / 5 + $day ))
s=$(( ( ( (j-719606) * 24 + $hour ) * 60 + $min ) * 60 + $sec ))

# 7  
Old 10-07-2009
Quote:
Originally Posted by cfajohnson

Translated to portable syntax that will run in any POSIX shell:

Code:
mon=$(( $mon + 1 ))
if [ $mon -lt 4 ]
then
   year=$(( $year - 1 ))
   mon=$(( mon + 12 ))
fi
j=$(( $year * 1461 / 4 + mon * 153 / 5 + $day ))
s=$(( ( ( (j-719606) * 24 + $hour ) * 60 + $min ) * 60 + $sec ))


I don't think you can do the $(( syntax in bourne shell...

my code was written for bourne shell as we dont run ksh or bash in our network.
Login or Register to Ask a Question

Previous Thread | Next Thread

8 More Discussions You Might Find Interesting

1. Cybersecurity

Log Review- SU

Hi, Can some please provide some hints on what to look for in unix/Linux logs such as sulog from a Information security perspective. Regards (2 Replies)
Discussion started by: Tilus
2 Replies

2. Shell Programming and Scripting

Peer Review File/Folder Script

Hello *nix friends, I've written a shell script that allow web admin's to copy file/folder from a development site to the production site. It's more or less a poor man SVN. I'm posting the script here because I was able to get many questions answered through this forum and also, I want to... (4 Replies)
Discussion started by: rwhite35
4 Replies

3. Shell Programming and Scripting

Please review error routines in my ksh script

The script distributes files from an AIX server using iether ftp or sftp depending on the constraint of the destination server. I am interested in having the error checking routine critically reviewed. I will only include an excerpt from the script concerning error trapping: (where $FTP_OUT is the... (7 Replies)
Discussion started by: peleton
7 Replies

4. UNIX for Dummies Questions & Answers

Question/review my script: removing bad chars from filenames

The task: remove undesirable characters from filenames. Restrictions: Must use basic RE, base utilities (non-GNU) and /bin/sh (ash). No ksh, zsh, perl, etc. Below is what I've come up with. It seems to work OK but I'm open to shorter, more efficient alternatives. Inside the square... (4 Replies)
Discussion started by: uiop44
4 Replies

5. Shell Programming and Scripting

Please review script for search in all files

I have written a little script to scan users home directories for certain commands located inside a file. The script is setup to include a small help section and allows for passing a username argument to override scanning of all users home directories. A lot of searching and trial and error has... (7 Replies)
Discussion started by: bkeep
7 Replies

6. Shell Programming and Scripting

Review Check list for Unix Shell Script

Hi, I need Unix Shell Script Review Check list in the format of word or excel. Can any one provide the review checklist for unix shell script. Pls. (1 Reply)
Discussion started by: praka
1 Replies

7. Shell Programming and Scripting

Please, review script.

Hi guys, I 've been brewing this shellscript, but I can't test it until next tuesday. In the meantime I am too curious wether it will work or not, so I'd like to hear your comments. Background: I want to watch the user quota for mailboxes in various email-domains on a IMAP-server. I have... (1 Reply)
Discussion started by: algernonz
1 Replies

8. Shell Programming and Scripting

Review the Shell Script

Hi, I want to copy all the log file except current date log from one server to another server. Log File will be like this LOGNIG_08_11_2008*.log For this cd /test/log date -d '1 day ago' "+%d_%m_%Y" -->This command gives previous day scp LOGSNIG_date -d '1 day ago' "+%d_%m_%Y"... (2 Replies)
Discussion started by: srinivasvandana
2 Replies
Login or Register to Ask a Question