Скрипт оболочки с CGI отлично работает с bash, но не с sh - PullRequest
1 голос
/ 23 января 2012

Я нашел следующий рабочий пример CGI с bash. Если я изменю первые две строки на

#!/bin/sh
echo "Content-type: text/html\n\n"

после того, как скрипт перестает работать, и когда я просматриваю скрипт в браузере, «foo», «bar» и «foobar», объявленные внизу скрипта, исчезают.

Любая идея, как заставить этот же пример работать с sh. На самом деле мне нужно запустить такой пример на встроенном устройстве, где у меня нет bash, но sh.

<code>#!/bin/bash
echo -e "Content-type: text/html\n\n"
echo "
<html>
<body>
<form action="http://${HTTP_HOST}:${SERVER_PORT}${SCRIPT_NAME}?foo=1234" method="POST">
<input type="text" name="bar">
<textarea name="foobar"></textarea>
<input type="submit">
</form>"


# (internal) routine to store POST data
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 "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
    return
}

# (internal) routine to decode urlencoded strings
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
cgi_getvars()
{
    [ $# -lt 2 ] && return
    local q p k v s
    # 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

echo "<pre>foo=$foo
» эхо "
bar=$bar
" echo "
foobar=$foobar
" эхо " »

Обновление 1: sh -x script вернул следующее:

<code>+ echo Content-type: text/html\n\n
Content-type: text/html


+ echo 
<html>
<body>
<form action=http://:?foo=1234 method=POST>
<input type=text name=bar>
<textarea name=foobar></textarea>
<input type=submit>
</form>

<html>
<body>
<form action=http://:?foo=1234 method=POST>
<input type=text name=bar>
<textarea name=foobar></textarea>
<input type=submit>
</form>
+ cgi_getvars BOTH ALL
+ [ 2 -lt 2 ]
+ local q p k v s
+ [ ! -z  ]
+ cgi_get_POST_vars
+ [  != application/x-www-form-urlencoded ]
+ echo Warning: you should probably use MIME type  application/x-www-form-urlencoded!
Warning: you should probably use MIME type  application/x-www-form-urlencoded!
+ [ -z  -a  = POST -a ! -z  ]
+ return
+ [ ! -z  ]
+ shift
+ s= ALL 
+ [ ! -z  ]
+ return
+ echo <pre>foo=
foo=
+ эхо
bar=
bar=
+ эхо
foobar=
foobar=
+ эхо

Ответы [ 3 ]

2 голосов
/ 23 января 2012

Bash имеет множество расширений по сравнению со спецификацией POSIX, и ваш скрипт использует некоторые из них. Ваш /bin/sh явно не bash (может быть ash, dash, mksh или что-то в этом роде) и не имеет этих расширений. Вам нужно будет пройти через скрипт и проверить каждую конструкцию по документации вашего sh или спецификации POSIX .

Беглый взгляд:

  • function cgi_get_POST_vars(): ключевого слова функции не должно быть, и открывающая скобка должна идти в той же строке.
  • read -n $CONTENT_LENGTH QUERY_STRING_POST: read (встроенная оболочка) не имеет опции -n в POSIX.
  • t="${1//+/ }%%", h=${t:0:2}: Bourne не поддерживает ни один из этих модификаторов.

но могут быть и другие.

Edit:

  • echo - самая несовместимая команда между оболочками. Стандарт просто говорит, что поведение с \ определяется реализацией. Вы должны использовать printf вместо.
1 голос
/ 23 января 2012

Объявления функций с ключевым словом function несовместимы со скриптами Bourne. Правильный синтаксис для sh:

cgi_get_POST_vars() {
    ...
}
0 голосов
/ 01 февраля 2012

Также будьте очень осторожны с такими скриптами.Этот анализатор аргументов подвержен атаке инъекций оболочки.Например, если передана переменная:

cgi-bin/myscript.cgi&foo=bar`ls`bar

Я считаю, что команда "ls" будет выполнена во время декодирования аргумента.И вы можете представить себе гораздо более разрушительные команды, чем "ls".Также подумайте, что произойдет, если аргумент &PATH="" передан враждебным пользователем.Это сложно понять, и если вы имеете дело со встроенным устройством, я не удивлюсь, если веб-сервер работает с привилегиями root.

...