Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

return to calling cgi in bash script

Posted on 2013-11-01
6
Medium Priority
?
901 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 2000 total points
ID: 39618753
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
ID: 39618778
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
ID: 39618864
So, did removing the outputting of the unwanted content-type header and adding the colon fix the problem?
0
Ask an Anonymous Question!

Don't feel intimidated by what you don't know. Ask your question anonymously. It's easy! Learn more and upgrade.

 

Author Comment

by:Owen_Parker
ID: 39619169
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
ID: 39620478
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
ID: 39620489
You're welcome. :)
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to provide a dynamic RTF document on your website generated with data from your database. For this tutorial you will need Microsoft Word or WordPad, WhizBase and Microsoft Access. In this tutorial I will show …
Originally, this post was published on Monitis Blog, you can check it here . In business circles, we sometimes hear that today is the “age of the customer.” And so it is. Thanks to the enormous advances over the past few years in consumer techno…
Learn the basics of strings in Python: declaration, operations, indices, and slicing. Strings are declared with quotations; for example: s = "string": Strings are immutable.: Strings may be concatenated or multiplied using the addition and multiplic…
Learn the basics of if, else, and elif statements in Python 2.7. Use "if" statements to test a specified condition.: The structure of an if statement is as follows: (CODE) Use "else" statements to allow the execution of an alternative, if the …
Suggested Courses

885 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