Solved

return to calling cgi in bash script

Posted on 2013-11-01
6
831 Views
Last Modified: 2013-12-25
i probably can't find this explained anywhere because it's ridiculously easy or I am not supposed to do this in the first place, however, I need to accomplish some form of this.

Throwing together a gui to allow our installers to do very basic linux functions on a little linux server we are using for a gateway.  The linux server is very barebones so I get to learn some bash.

In this example, I am popping a simple webform to get the date month and year and will run a simple bash script to change the date and then load up the main menu again.  All is fine up until I try and load up the URL I want.  I know many ways to do this in many languages, but bash isn't behaving.  I probably have a space somewhere I shouldn't or some such silliness, but I am willing to be humiliated to move on  :)

There is zero chance of security issues here so no scolding on the sudo stuff.

setdate cgi - trimmed down as much as possible:

#!/bin/bash
echo "Content-type: text/html"
echo ""
echo "<html><head><title>Set the System Date"
echo "</title></head>"
echo "<body>"
echo "<FORM ACTION=dosetdate.cgi METHOD=POST>"
echo "Enter the date to set:"
echo "<select name=day size=1>"
echo "   <option value=1>1</option>"
echo "   <option value=2>2</option>"
echo "   <option value=3>3</option>"
echo "</select>"
echo "<select name=month size=1>"
echo "   <option value=JAN>JAN</option>"
echo "   <option value=FEB>FEB</option>"
echo "</select>"
echo "<select name=year size=1>"
echo "   <option value=2013>2013</option>"
echo "   <option value=2014>2014</option>"
echo "</select>"
echo "<input type=submit value=Submit>"
echo "</form>"
echo "</body></html>"

Open in new window


dosetdate.cgi - most of this is copy/pasted from a well known example online

#!/bin/bash
echo "Content-type: text/html"

# (internal) routine to store POST data
function cgi_get_POST_vars()
{
    # check content type
    # FIXME: not sure if we could handle uploads with this..
    [ "${CONTENT_TYPE}" != "application/x-www-form-urlencoded" ] && \
    #echo "bash.cgi warning: you should probably use MIME type "\
    #     "application/x-www-form-urlencoded!" 1>&2
    # save POST variables (only first time this is called)
    [ -z "$QUERY_STRING_POST" \
      -a "$REQUEST_METHOD" = "POST" -a ! -z "$CONTENT_LENGTH" ] && \
        read -n $CONTENT_LENGTH QUERY_STRING_POST
    # prevent shell execution
    local t
    t=${QUERY_STRING_POST//%60//} # %60 = `
    t=${t//\`//}
    t=${t//\$(//}
    QUERY_STRING_POST=${t}
    return
}

# (internal) routine to decode urlencoded strings
function cgi_decodevar()
{
    [ $# -ne 1 ] && return
    local v t h
    # replace all + with whitespace and append %%
    t="${1//+/ }%%"
    while [ ${#t} -gt 0 -a "${t}" != "%" ]; do
    v="${v}${t%%\%*}" # digest up to the first %
    t="${t#*%}"       # remove digested part
    # decode if there is anything to decode and if not at end of string
    if [ ${#t} -gt 0 -a "${t}" != "%" ]; then
        h=${t:0:2} # save first two chars
        t="${t:2}" # remove these
        v="${v}"`echo -e \\\\x${h}` # convert hex to special char
    fi
    done
    # return decoded string
    echo "${v}"
    return
}

# routine to get variables from http requests
# usage: cgi_getvars method varname1 [.. varnameN]
# method is either GET or POST or BOTH
# the magic varible name ALL gets everything
function cgi_getvars()
{
    [ $# -lt 2 ] && return
    local q p k v s
    # prevent shell execution
    t=${QUERY_STRING//%60//} # %60 = `
    t=${t//\`//}
    t=${t//\$(//}
    QUERY_STRING=${t}
    # get query
    case $1 in
    GET)
        [ ! -z "${QUERY_STRING}" ] && q="${QUERY_STRING}&"
        ;;
    POST)
        cgi_get_POST_vars
        [ ! -z "${QUERY_STRING_POST}" ] && q="${QUERY_STRING_POST}&"
        ;;
    BOTH)
        [ ! -z "${QUERY_STRING}" ] && q="${QUERY_STRING}&"
        cgi_get_POST_vars
        [ ! -z "${QUERY_STRING_POST}" ] && q="${q}${QUERY_STRING_POST}&"
        ;;
    esac
    shift
    s=" $* "
    # parse the query data
    while [ ! -z "$q" ]; do
    p="${q%%&*}"  # get first part of query string
    k="${p%%=*}"  # get the key (variable name) from it
    v="${p#*=}"   # get the value from it
    q="${q#$p&*}" # strip first part from query string
    # decode and evaluate var if requested
    [ "$1" = "ALL" -o "${s/ $k /}" != "$s" ] && \
        eval "$k=\"`cgi_decodevar \"$v\"`\""
    done
    return
}



# register all GET and POST variables
cgi_getvars BOTH ALL

datestring="$day $month $year 01:00:00"

/usr/bin/sudo /bin/su -c "/bin/date -s '$datestring' >/dev/null 2>&1"

url="http://172.22.22.22/cgi-bin/setdate.cgi"

echo "Location $url"

Open in new window



Now I am very aware that the final line could not possibly work.  However, I have not been able to come up with anything else.  In a perl script, I would simply print this and it would open the url specified.  How can this be accomplished in bash?

Thanks in advance

O
0
Comment
Question by:Owen_Parker
  • 3
  • 3
6 Comments
 
LVL 28

Accepted Solution

by:
FishMonger earned 500 total points
Comment Utility
I don't do bash scripting but, I'd start by removing the output of the Content-Type on line 2.

Also, I believe you need a colon after Location.
echo "Location: $url"

Open in new window

This might be a silly question but, since it sounds like you already know how to do this in Perl, why not use it instead of bash?  You'd be able to reduce the dosetdate.cgi script by about 80%.

Here's the minimalist version of the perl script.
#!/usr/bin/perl

use strict;
use warnings;
use CGI;

my $cgi        = CGI->new;
my %param      = $cgi->Vars;
my $datestring = "$param{day} $param{month} $param{year} 01:00:00";
my $url        = "http://172.22.22.22/cgi-bin/setdate.cgi";

# there are multiple ways to run this command, and this may not be the best
system( qq(/usr/bin/sudo /bin/su -c "/bin/date -s '$datestring' >/dev/null 2>&1") );

print $cgi->redirect($url);

Open in new window

0
 

Author Comment

by:Owen_Parker
Comment Utility
Hi FishMonger

You are right on the colon after location.  That was a typo somehow.  As for doing this in bash versus perl, I had inherited this little project and the device it is running on has only a 1 GB flash for storage and I was told it was a very stripped down version of OpenSuse and not much could be done on it.  When asked to add some sort of interface, it was suggested it be done in bash due to the limitations.  So, I did it all in bash.  This and one other similar function is all that is left.  And this one little part is all that is left of those.  However, before i started answering you, I asked myself when was the last time I saw ANY linux install that didn't have perl installed.  So I type perl -v and lo and behold, perl is installed after all.  LOL

Learned a couple lessons there I guess.

However, now there is this issue with bash, and I must resolve it.  Knowing I can finish this in 15 minutes now is reassuring.  but I'm not very good at dealing with an unresolved issue, other than to find the solution!  

I thank you for asking the very obvious question and leading me to spend the 1.3 seconds checking something i should have checked a week ago!  :)
0
 
LVL 28

Expert Comment

by:FishMonger
Comment Utility
So, did removing the outputting of the unwanted content-type header and adding the colon fix the problem?
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:Owen_Parker
Comment Utility
No, sorry, I thought that was implied.  Same basic end result.  The echoing of the string "Location: and the URL to the screen.
0
 

Author Closing Comment

by:Owen_Parker
Comment Utility
I never did receive the solution to my query, but since I could do it in Perl, I did.  I will see about getting the solution from my engineer Monday and will post it here for future reference if it is resolvable...  Thanks for your input FishMonger...  It was surely helpful...
0
 
LVL 28

Expert Comment

by:FishMonger
Comment Utility
You're welcome. :)
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

It is a general practice to get rid of old user profiles on a computer  in a LAN environment. As I have been working with a company in a LAN environment where users move from one place to some other place at times. This will make many user profil…
Active Directory replication delay is the cause to many problems.  Here is a super easy script to force Active Directory replication to all sites with by using an elevated PowerShell command prompt, and a tool to verify your changes.
The viewer will learn how to count occurrences of each item in an array.
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now