Provided by: haserl_0.9.32-1_amd64 bug

NAME

       haserl - A cgi scripting program for embedded environments

SYNOPSIS

       #!/usr/bin/haserl   [--shell=pathspec]  [--upload-dir=dirspec]  [--upload-handler=handler]
       [--upload-limit=limit] [--accept-all] [--accept-none] [--silent] [--debug]

       [ text ] [ <% shell script %> ] [ text ] ...

DESCRIPTION

       Haserl is a small cgi wrapper that allows "PHP" style cgi programming,  but  uses  a  UNIX
       bash-like  shell  or Lua  as the programming language. It is very small, so it can be used
       in embedded environments, or where something like PHP is too big.

       It combines three features into a small cgi engine:

              It parses POST and GET requests, placing form-elements as name=value pairs into the
              environment for the CGI script to use.  This is somewhat like the uncgi wrapper.

              It  opens  a  shell,  and  translates all text into printable statements.  All text
              within <% ... %> constructs are passed verbatim to the  shell.   This  is  somewhat
              like writing PHP scripts.

              It  can optionally be installed to drop its permissions to the owner of the script,
              giving it some of the security features of suexec or cgiwrapper.

OPTIONS SUMMARY

       This is a summary of the command-line options.  Please see the OPTIONS section  under  the
       long option name for a complete description.

       -a  --accept-all
       -n  --accept-none
       -d  --debug
       -s, --shell
       -S, --silent
       -U, --upload-dir
       -u, --upload-limit
       -H, --upload-handler

OPTIONS

       --accept-all
              The  program  normally  accepts  POST data only when the REQUEST_METHOD is POST and
              only accepts data on the URL  data when the REQUEST_METHOD is  GET.    This  option
              allows  both  POST  and  URL  data to be accepted regardless of the REQUEST_METHOD.
              When this option is set, the REQUEST_METHOD takes precedence (e.g.  if  the  method
              is  POST,  FORM_variables  are  taken from COOKIE data, GET data, and POST data, in
              that order.   If the method is GET, FORM_variables are taken from COOKIE data, POST
              data,  and  GET  data.)   The default is not to accept all input methods - just the
              COOKIE data and the REQUEST_METHOD.

       --accept-none
              If given, haserl will not parse standard input as http  content  before  processing
              the script.  This is useful if calling a haserl script from another haserl script.

       --debug
              Instead  of  executing the script, print out the script that would be executed.  If
              the environment variable 'REQUEST_METHOD'  is  set,  the  data  is  sent  with  the
              plain/text content type.  Otherwise, the shell script is printed verbatim.

       --shell=pathspec
              Specify an alternative bash-like shell to use. Defaults to "/bin/sh"

              To include shell parameters do not use the --shell=/bin/sh format. Instead, use the
              alternative format without the "=", as in --shell "/bin/bash --norc".  Be  sure  to
              quote the option string to protect any special characters.

              If  compiled with Lua libraries, then the string "lua" is used to use an integrated
              Lua vm.  This string is case sensitive.  Example: --shell=lua

              An alternative is "luac".  This causes the haserl and lua parsers to  be  disabled,
              and  the  script is assumed to be a precompiled lua chunk.  See LUAC below for more
              information.

       --silent
              Haserl  normally  prints  an  informational  message  on  error  conditions.   This
              suppresses the error message, so that the use of haserl is not advertised.

       --upload-dir=dirspec
              Defaults  to "/tmp". All uploaded files are created with temporary filename in this
              directory HASERL_xxx_path contains the name of the  temporary  file.  FORM_xxx_name
              contains the original name of the file, as specified by the client.

       --upload-handler=pathspec
              When  specified,  file  uploads are handled by this handler, rather than written to
              temporary files.  The full pathspec must be given (the PATH is not  searched),  and
              the  upload-handler  is  given  one command-line parameter: The name of the FIFO on
              which the upload file will be  sent.   In  addition,  the  handler  may  receive  3
              environment  variables:  CONTENT_TYPE,  FILENAME, and NAME.  These reflect the MIME
              content-disposition headers for the content. Haserl will fork the handler for  each
              file uploaded, and will send the contents of the upload file to the specified FIFO.
              Haserl will then block until the handler terminates.  This method  is  for  experts
              only.

       --upload-limit=limit
              Allow  a  mime-encoded  file up to limit KB to be uploaded.  The default is 0KB (no
              uploads allowed).  Note that mime-encoding adds 33% to the size of the data.

OVERVIEW OF OPERATION

       In general, the web server sets up several environment variables, and then  uses  fork  or
       another  method  to  run  the  CGI script.  If the script uses the haserl interpreter, the
       following happens:

              If haserl is installed suid root, then uid/gid is set to the owner of the script.

              The environment is scanned for HTTP_COOKIE, which may have  been  set  by  the  web
              server.   If it exists, the parsed contents are placed in the local environment.

              The  environment  is  scanned  for REQUEST_METHOD, which was set by the web server.
              Based on the request method,  standard  input  is  read  and  parsed.   The  parsed
              contents are placed in the local environment.

              The  script  is  tokenized,  parsing haserl code blocks from raw text.  Raw text is
              converted into "echo" statements, and then all tokens are sent to the sub-shell.

              haserl forks and a sub-shell (typically /bin/sh) is started.

              All tokens are sent to the STDIN of the sub-shell, with a trailing exit command.

              When the sub-shell terminates, the haserl interpreter performs  final  cleanup  and
              then terminates.

CLIENT SIDE INPUT

       The haserl interpreter will decode data sent via the HTTP_COOKIE environment variable, and
       the GET or POST method from the client, and store them as environment variables  that  can
       be  accessed  by  haserl.   The name of the variable follows the name given in the source,
       except that a prefix ( FORM_) is prepended.  For example, if the client  sends  "foo=bar",
       the environment variable is FORM_foo=bar.

       For  the  HTTP_COOKIE  method, variables are also stored with the prefix ( COOKIE_) added.
       For  example,  if  HTTP_COOKIE   includes   "foo=bar",   the   environment   variable   is
       COOKIE_foo=bar.

       For  the  GET  method,  data  sent  in the form %xx is translated into the characters they
       represent, and variables are also stored with the prefix ( GET_) added.  For  example,  if
       QUERY_STRING includes "foo=bar", the environment variable is GET_foo=bar.

       For  the  POST  method,  variables  are  also  stored with the prefix ( POST_) added.  For
       example, if the post stream includes "foo=bar", the environment variable is POST_foo=bar.

       Also, for the POST method, if the data is sent  using  multipart/form-data  encoding,  the
       data is automatically decoded.   This is typically used when files are uploaded from a web
       client using <input type=file>.

       NOTE   When a file is uploaded  to  the  web  server,  it  is  stored  in  the  upload-dir
              directory.   FORM_variable_name=  contains  the  name  of  the  file  uploaded  (as
              specified by the client.)  HASERL_variable_path= contains the name of the  file  in
              upload-dir  that  holds  the  uploaded content.   To prevent malicious clients from
              filling up upload-dir on your web server, file uploads are only  allowed  when  the
              --upload-limit option is used to specify how large a file can be uploaded.   Haserl
              automatically deletes the temporary file when the script is finished.  To keep  the
              file, move it or rename it somewhere in the script.

              Note that the filename is stored in HASERL_variable_path This is because the FORM_,
              GET_, and POST_ variables are modifiable by the client, and a malicious client  can
              set  a  second  variable with the name variable_path=/etc/passwd.  Earlier versions
              did  not  store  the  pathspec  in  HASERL   namespace.    To   maintain   backward
              compailibility, the name of the temporary file is also stored in FORM_variable= and
              POST_variable=. This is considered unsafe and should not be used.

       If the client sends data both by POST and GET methods, then haserl  will  parse  only  the
       data  that  corresponds with the REQUEST_METHOD variable set by the web server, unless the
       accept-all option has been set.   For example, a form called via POST method, but having a
       URI  of  some.cgi?foo=bar&otherdata=something  will have the POST data parsed, and the foo
       and otherdata variables are ignored.

       If the web server defines a HTTP_COOKIE environment variable, the cookie data  is  parsed.
       Cookie data is parsed before the GET or POST data, so in the event of two variables of the
       same name, the GET or POST data overwrites the cookie information.

       When multiple instances of  the  same  variable  are  sent  from  different  sources,  the
       FORM_variable  will  be  set  according  to  the  order  in which variables are processed.
       HTTP_COOKIE is always processed first, followed by the REQUEST_METHOD.  If the  accept-all
       option  has  been  set,  then  HTTP_COOKIE  is processed first, followed by the method not
       specified by REQUEST_METHOD, followed by the REQUEST_METHOD.  The  last  instance  of  the
       variable  will  be used to set FORM_variable.  Note that the variables are also separately
       creates as COOKIE_variable, GET_variable  and  POST_variable.   This  allows  the  use  of
       overlapping names from each source.

       When  multiple instances of the same variable are sent from the same source, only the last
       one is saved.  To keep all copies (for multi-selects, for instance), add "[]" to  the  end
       of the variable name.  All results will be returned, separated by newlines.   For example,
       host=Enoch&host=Esther&host=Joshua         results         in          "FORM_host=Joshua".
       host[]=Enoch&host[]Esther&host[]=Joshua results in "FORM_host=Enoch\nEsther\nJoshua"

LANGUAGE

       The following language structures are recognized by haserl.

       RUN
              <% [shell script] %>

              Anything  enclosed by <% %> tags is sent to the sub-shell for execution.   The text
              is sent verbatim.

       INCLUDE
              <%in pathspec %>

              Include another file verbatim in this script.  The file is included when the script
              is initially parsed.

       EVAL
              <%= expression %>

              print the shell expression.  Syntactic sugar for "echo expr".

       COMMENT
              <%# comment %>

              Comment  block.  Anything in a comment block is not parsed.  Comments can be nested
              and can contain other haserl elements.

EXAMPLES

       WARNING
              The examples below are simplified to  show  how  to  use  haserl.   You  should  be
              familiar  with  basic  web scripting security before using haserl (or any scripting
              language) in a production environment.

       Simple Command
              #!/usr/local/bin/haserl
              content-type: text/plain

              <%# This is a sample "env" script %>
              <% env %>

              Prints the results of the env command as a mime-type "text/plain" document. This is
              the haserl version of the common printenv cgi.

       Looping with dynamic output
              #!/usr/local/bin/haserl
              Content-type: text/html

              <html>
              <body>
              <table border=1><tr>
              <% for a in Red Blue Yellow Cyan; do %>
                   <td bgcolor="<% echo -n "$a" %>"><% echo -n "$a" %></td>
                   <% done %>
              </tr></table>
              </body>
              </html>

              Sends  a  mime-type  "text/html" document to the client, with an html table of with
              elements labeled with the background color.

       Use Shell defined functions.
              #!/usr/local/bin/haserl
              content-type: text/html

              <% # define a user function
                 table_element() {
                     echo "<td bgcolor=\"$1\">$1</td>"
                  }
                 %>
              <html>
              <body>
              <table border=1><tr>
              <% for a in Red Blue Yellow Cyan; do %>
                   <% table_element $a %>
                   <% done %>
              </tr></table>
              </body>
              </html>

              Same as above, but uses a shell function instead of embedded html.

       Self Referencing CGI with a form
              #!/usr/local/bin/haserl
              content-type: text/html

              <html><body>
              <h1>Sample Form</h1>
              <form action="<% echo -n $SCRIPT_NAME %>" method="GET">
              <% # Do some basic validation of FORM_textfield
                 # To prevent common web attacks
                 FORM_textfield=$( echo "$FORM_textfield" | sed "s/[^A-Za-z0-9 ]//g" )
                 %>
              <input type=text name=textfield
                   Value="<% echo -n "$FORM_textfield" | tr a-z A-Z %>" cols=20>
              <input type=submit value=GO>
              </form></html>
              </body>

              Prints a form.  If the client enters text in the form, the CGI is reloaded (defined
              by  $SCRIPT_NAME)  and  the textfield is sanitized to prevent web attacks, then the
              form is redisplayed with the text the user entered.  The text is uppercased.

       Uploading a File
              #!/usr/local/bin/haserl --upload-limit=4096 --upload-dir=/tmp
              content-type: text/html

              <html><body>
              <form action="<% echo -n $SCRIPT_NAME %>" method=POST enctype="multipart/form-data" >
              <input type=file name=uploadfile>
              <input type=submit value=GO>
              <br>
              <% if test -n "$HASERL_uploadfile_path"; then %>
                      <p>
                      You uploaded a file named <b><% echo -n $FORM_uploadfile_name %></b>, and it was
                      temporarily stored on the server as <i><% echo $HASERL_uploadfile_path %></i>.  The
                      file was <% cat $HASERL_uploadfile_path | wc -c %> bytes long.</p>
                      <% rm -f $HASERL_uploadfile_path %><p>Don't worry, the file has just been deleted
                      from the web server.</p>
              <% else %>
                      You haven't uploaded a file yet.
              <% fi %>
              </form>
              </body></html>

              Displays a form that allows for file uploading.  This is accomplished by using  the
              --upload-limit  and  by  setting  the  form enctype to multipart/form-data.  If the
              client sends a file, then some information regarding the file is printed, and  then
              deleted.  Otherwise, the form states that the client has not uploaded a file.

       RFC-2616 Conformance
              #!/usr/local/bin/haserl
              <% echo -en "content-type: text/html\r\n\r\n" %>
              <html><body>
                ...
              </body></html>

              To  fully  comply  with  the HTTP specification, headers should be terminated using
              CR+LF, rather than the normal unix LF line termination only.  The above syntax  can
              be used to produce RFC 2616 compliant headers.

ENVIRONMENT

       In  addition  to  the  environment  variables inherited from the web server, the following
       environment variables are always defined at startup:

       HASERLVER
              haserl version - an informational tag.

       SESSIONID
              A hexadecimal tag that is unique for the life of the CGI (it is generated when  the
              cgi starts; and does not change until another POST or GET query is generated.)

       HASERL_ACCEPT_ALL
              If the --accept-all flag was set, -1, otherwise 0.

       HASERL_SHELL
              The name of the shell haserl started to run sub-shell commands in.

       HASERL_UPLOAD_DIR
              The directory haserl will use to store uploaded files.

       HASERL_UPLOAD_LIMIT
              The number of KB that are allowed to be sent from the client to the server.

       These  variables  can  be  modified  or  overwritten  within the script, although the ones
       starting with "HASERL_" are informational only, and do not affect the running script.

SAFETY FEATURES

       There is much literature regarding the dangers of using  shell  to  program  CGI  scripts.
       haserl contains some protections to mitigate this risk.

       Environment Variables
              The  code  to  populate  the environment variables is outside the scope of the sub-
              shell.   It parses on the characters ? and  &, so it is harder for a client  to  do
              "injection" attacks.  As an example, foo.cgi?a=test;cat /etc/passwd could result in
              a variable being assigned the value test  and  then  the  results  of  running  cat
              /etc/passwd being sent to the client.  Haserl will assign the variable the complete
              value: test;cat /etc/passwd

              It is safe to use this "dangerous" variable in shell scripts  by  enclosing  it  in
              quotes; although validation should be done on all input fields.

       Privilege Dropping
              If  installed as a suid script, haserl will set its uid/gid to that of the owner of
              the script.  This can be used to have a  set  of  CGI  scripts  that  have  various
              privilege.   If  the haserl binary is not installed suid, then the CGI scripts will
              run with the uid/gid of the web server.

       Reject command line parameters given on the URL
              If the URL does not contain an unencoded "=", then the CGI spec states the  options
              are  to be used as command-line parameters to the program.  For instance, according
              to the CGI spec: http://192.168.0.1/test.cgi?--upload-limit%3d2000&foo%3dbar
              Should set the upload-limit to 2000KB in addition to setting "Foo=bar".  To protect
              against clients enabling their own uploads, haserl rejects any command-line options
              beyond argv[2].   If invoked as a #!   script,  the  interpreter  is  argv[0],  all
              command-line  options  listed  in  the  #!  line are combined into argv[1], and the
              script name is argv[2].

LUA

       If compiled with lua support, --shell=lua will enable lua as the script  language  instead
       of  bash  shell.   The environment variables (SCRIPT_NAME, SERVER_NAME, etc) are placed in
       the ENV table, and the form variables are placed in the  FORM  table.   For  example,  the
       self-referencing form above can be written like this:

              #!/usr/local/bin/haserl --shell=lua
              content-type: text/html

              <html><body>
              <h1>Sample Form</h1>
              <form action="<% io.write(ENV["SCRIPT_NAME"]) %>" method="GET">
              <% # Do some basic validation of FORM_textfield
                 # To prevent common web attacks
                 FORM.textfield=string.gsub(FORM.textfield, "[^%a%d]", "")
                 %>
              <input type=text name=textfield
                   Value="<% io.write (string.upper(FORM.textfield)) %>" cols=20>
              <input type=submit value=GO>
              </form></html>
              </body>

       The  <%=  operator  is syntactic sugar for io.write (tostring( ... )) So, for example, the
       Value= line above could be written: Value="<%= string.upper(FORM.textfield) %>" cols=20>

       haserl lua scripts can use the function  haserl.loadfile(filename)  to  process  a  target
       script as a haserl (lua) script.  The function returns a type of "function".

       For example,

       bar.lsp
              <% io.write ("Hello World" ) %>

              Your message is <%= gvar %>

              -- End of Include file --

       foo.haserl
              #!/usr/local/bin/haserl --shell=lua
              <% m = haserl.loadfile("bar.lsp")
                 gvar = "Run as m()"
                 m()

                 gvar = "Load and run in one step"
                 haserl.loadfile("bar.lsp")()
              %>

       Running foo will produce:

              Hello World
              Your message is Run as m()
              -- End of Include file --
              Hello World
              Your message is Load and run in one step
              -- End of Include file --

              This  function makes it possible to have nested haserl server pages - page snippets
              that are processed by the haserl tokenizer.

LUAC

       The luac "shell" is a precompiled lua chunk, so interactive editing and testing of scripts
       is  not  possible. However, haserl can be compiled with luac support only, and this allows
       lua support even in a small memory environment.  All haserl lua features listed above  are
       still  available.   (If  luac  is the only shell built into haserl, the haserl.loadfile is
       disabled, as the haserl parser is not compiled in.)

       Here is an example of a trivial script, converted into a luac cgi script:

       Given the file test.lua:
              print ("Content-Type: text/plain0)
              print ("Your UUID for this run is: " .. ENV.SESSIONID)

       It can be compiled with luac:
              luac -o test.luac -s test.lua

       And then the haserl header added to it:
              echo '#!/usr/bin/haserl --shell=luac' | cat - test.luac  >luac.cgi

       Alternatively, it is possible to develop an entire website using the standard  lua  shell,
       and  then  have  haserl  itself  preprocess the scripts for the luac compiler as part of a
       build process.  To do this, use --shell=lua, and develop the website.  When ready to build
       the runtime environment, add the --debug line to your lua scripts, and run them outputting
       the results to .lua source files.  For example:

       Given the haserl script test.cgi:
              #!/usr/bin/haserl --shell=lua --debug
              Content-Type: text/plain

              Your UUID for this run is <%= ENV.SESSIONID %>

       Precompile, compile, and add the haserl luac header:
              ./test.cgi > test.lua
              luac -s -o test.luac test.lua
              echo '#!/usr/bin/haserl --shell=luac' | cat - test.luac >luac.cgi

BUGS

       Old versions of haserl used <? ?> as token markers, instead of <% %>.   Haserl  will  fall
       back to using <? ?> if <% does not appear anywhere in the script.

       When files are uploaded using RFC-2388, a temporary file is created.  The name of the file
       is  stored  in  FORM_variable_name,  POST_variable_name,  and  HASERL_variable_name.  Only
       HASERL_variable_name should be used - the others can be overwritten by a malicious client.

NAME

       The  name  "haserl"  comes  from  the Bavarian word for "bunny." At first glance it may be
       small and cute, but haserl is more like the bunny from Monty Python & The Holy Grail.   In
       the  words  of  Tim the Wizard, That's the most foul, cruel & bad-tempered rodent you ever
       set eyes on!

       Haserl can be thought of the cgi equivalent to netcat.  Both are small, powerful, and have
       very little in the way of extra features.  Like netcat, haserl attempts to do its job with
       the least amount of extra "fluff".

AUTHOR

       Nathan Angelacos <nangel@users.sourceforge.net>

SEE ALSO

       php(http://www.php.net)                 uncgi(http://www.midwinter.com/~koreth/uncgi.html)
       cgiwrapper(http://cgiwrapper.sourceforge.net)

                                           October 2010                                 haserl(1)