SQLite Forum

"Hello, world" CGI with althttpd
Login

"Hello, world" CGI with althttpd

(1.1) By Stephen Weigand (weigand) on 2021-01-16 05:56:12 edited from 1.0 [link] [source]

Hi,

With the ultimate goal of using Althttpd to serve one or more Fossil repositories, I've got Althttpd set up and successfully serving a family member's static website using the instructions at althttpd.md.

For the family member's website, there are HTTP and HTTPS versions but I've temporarily hijacked the http service to see if I can get CGI working. This is what I changed /etc/xinet.d/http to:

service http
{
  port = 80
  flags = IPv4
  socket_type = stream
  wait = no
  user = root
  server = /usr/bin/althttpd
  server_args = -logfile /logs/http.log -root /home/weigand/www -user weigand
  bind = 45.56.75.81
}

service http
{
  port = 80
  flags = REUSE IPv6
  bind = 2600:3c00::f03c:92ff:febb:f36f
  socket_type = stream
  wait = no
  user = root
  server = /usr/bin/althttpd
  server_args = -logfile /logs/http.log -root /home/weigand/www -user weigand
}

To rule in or rule out something obvious, here are my home directory permissions:

 drwxr-xr-x 15 weigand weigand 4096 Jan 16 04:16 /home/weigand

These are the web "root" directory permissions:

 drwxr-xr-x 4 weigand weigand 4096 Jan 15 22:22 /home/weigand/www

These are the files inside 'www' and their permissions:

 drwxr-xr-x 2 weigand weigand 4096 Jan 16 04:11 www_hoskin_ga.website
 drwxr-xr-x 2 weigand weigand 4096 Jan 15 22:22 logs

These are the files in 'www_hoskin_ga.website' and their permissions (with hello being my CGI script):

 -rwxr-xr-x 1 weigand weigand 73 Jan 16 03:51 hello
 -rw-r--r-- 1 weigand weigand 15 Jan 15 21:56 index.html

The content of the CGI file hello is:

#!/bin/bash
printf "Content-type: text/html\r\n\r\n" # Need 2 breaks per Stephan Beal's reply
printf "Hello, World!\n"

For some reason, when I go to http://www.hoskin.ga/hello, I see a blank page but get a 200 response.

The last line of the log file is:

 2021-01-16 04:46:58,71.37.244.154,
 "http://www.hoskin.ga/hello","",200,355,101,
 2020,0,0,0,1426,1,
 "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:78.0) Gecko/20100101 Firefox/78.0",
 "",26,0

I would be grateful if anybody could spot a problem or make a suggestion.

With appreciation,

Stephen

(2) By Stephan Beal (stephan) on 2021-01-16 05:19:08 in reply to 1.0 [link] [source]

printf "Content-type: text/html\r\n"

i'm not sure if this is the problem, but you need a blank line after the headers. i.e. printf "Content-type: text/html\r\n\r\n"

(3) By Stephen Weigand (weigand) on 2021-01-16 05:37:44 in reply to 2 [link] [source]

Thank you for the quick reply! That makes sense and I made the change but it didn't solve the problem.

(4) By TripeHound on 2021-01-16 07:29:26 in reply to 3 [link] [source]

I'd be tempted to try either text/plain for the content-type, or make the message part something like <html><body><p>Hello, world!</p></body></html>.

(5) By Richard Hipp (drh) on 2021-01-16 13:12:03 in reply to 1.1 [link] [source]

Althttpd is being launched as root (due to the "user = root" line in your xinetd configuration) which means it will be putting itself into a chroot jail at /home/weigand/www. Probably /bin/bash is not contained within that jail. (For security reasons, it shouldn't be.)

Work-arounds:

  1. Change the xinetd configuration to say "user = weigand".

  2. Make a copy (a hard copy, not a symlink) of /bin/bash into /home/weigand/www/bin/bash. Also make similar copies of any shared libraries that /bin/bash depends upon into corresponding places under /home/weigand/www. You can find the shared libraries by running "ldd /bin/bash". There are several on my Ubuntu system. Hence, work-around #1 is probably more practical.

In all of my public-facing systems that run althttpd, I keep "user = root" and thus run everything out of a chroot jail. And I purposefully omit most unix utilities from that jail. There is no /bin/bash. All or most of the standard shared libraries are omitted. I do provide /dev/null and /dev/random, but not much else. This means that the CGI programs that I run (which are mostly just "fossil" and "wapptclsh") must be statically linked.

This is an extra layer of defense against exploits. Suppose someone finds an RCE in Fossil or Wapp. They won't be able to use that bug to shell-out since the chroot jail in which the program was running doesn't have a shell! Nor does it have basic utility programs like "mv" and "rm" and "ls". This does not make a zero-day vulnerability impossible to exploit, but it makes it a lot more difficult. Defense in depth.

(6) By Stephen Weigand (weigand) on 2021-01-16 15:19:15 in reply to 5 [source]

Thank you, Richard, for the detailed explanation. Approach #1 worked so that's great but also I now appreciate/understand better the implications of a chroot jail. (Kind of like, "Which part of the word jail did I not understand?")

So thank you again and thanks also to TripeHound for the content type fix. It's good to not have an error in one's "Hello, world" program. :)

(7) By anonymous on 2021-06-17 21:01:12 in reply to 5 [link] [source]

Dear All,

First: thanks for sqlite and althttpd. I'm in a similar boat, wanted to run #!/bin/bash => echo "Hello $RANDOM World" for proof of life and managed to get things configured via xinetd and serving static content.

Firstly, I had to learn a bit more about xinetd config and its relationship with /etc/services (and port numbers, etc). A helpful command for that was: /usr/sbin/xinetd -d -dontfork, along with systemctl start/stop xinetd The tutorial/documentation for althttpd does not mention /etc/services, and xinetd complains that ERROR: http is supposed to be on port 80 instead of 8088 (upon further reading: this is likely 100% on me, as :8080 would exist in /etc/services)

Secondly, when althttpd was running and failing to execute my *.cgi, httpd.log was not getting populated with any error messages, and from what I could tell there was no useful output/error messages coming to the browser. eg:

Without --jail

rames@red-slash:~/Public$ md5sum http.log 
1440a68f9dca1ec0eb2441ffa256f126  http.log
rames@red-slash:~/Public$ curl --verbose http://localhost:8088/bar
*   Trying 127.0.0.1:8088...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8088 (#0)
> GET /bar HTTP/1.1
> Host: localhost:8088
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Connection: keep-alive
< Date: Thu, 17 Jun 2021 20:37:39 GMT
< Content-length: 0
< 
* Connection #0 to host localhost left intact
rames@red-slash:~/Public$ md5sum http.log 
1440a68f9dca1ec0eb2441ffa256f126  http.log

With --jail 0

rames@red-slash:~/Public$ md5sum http.log 
1440a68f9dca1ec0eb2441ffa256f126  http.log
rames@red-slash:~/Public$ curl --verbose http://localhost:8088/bar
*   Trying 127.0.0.1:8088...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8088 (#0)
> GET /bar HTTP/1.1
> Host: localhost:8088
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Connection: keep-alive
< Date: Thu, 17 Jun 2021 20:38:42 GMT
< Content-type: text/html
< Content-length: 151
< 
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Hello World</title>
</head>
<body>
Hello 2541
</body>
</html>
* Connection #0 to host localhost left intact
rames@red-slash:~/Public$ md5sum http.log 
8135df716f6026da36971d1febcf0ffe  http.log

...you can see that in one case, a request was made, but there was no output and no entry in http.log, whereas in the "working" case, an entry was added to http.log.

If I hadn't stumbled upon this discussion (via google query: "althttpd" not executing bash), I really don't think I would have been able to figure out where my problem was.

althttpd --help is not recognized, and searching through althttpd.md for cgi, exec, and jail is quite unclear that there exists this subtle interaction that "you can only use static binaries and scripts of any kind are practically impossible". Anything with a shebang is likely to refer to something outside of the www-root, and on most linux systems, any typical shebang target will likely be dynamically (not statically) compiled.

I'll keep forging ahead with it, I'm hopeful that this will help me cobble something together for my home network/scripts (eg: ~/bin/turn-on-the-lights.sh) without a bunch of overhead managing "stuff". The simplicity of althttpd is appealing if I can get it working right.

Would doc-centric patches be welcome? eg: update Security Features => --jail && static binaries, what would a Troubleshooting section look like?