azpiuser
Posts: 17
Joined: Sun Jun 09, 2013 9:23 pm

GPIO through CGI

Sat Jan 10, 2015 7:28 am

Apparently the RPIO does not permit access to GPIO without root access - so a python script writing to GPIO needs to be run as "sudo xyz.py"

So I need to figure out a workaround for that. But, even before I get there, I'm trying to understand why this doesn't work. I put this file (date.py) in my /var/www/cgi-bin directoy (I'm running lighttpd) :

Code: Select all

#!/bin/sh
date >> /tmp/test$$.txt
If I run it from the command line, it does what you expect. But, when I go to 192.168.1.113/cgi-bin/date.py , I don't see an update in the /tmp directory. What am I missing?

Another curio, if I name the file date.sh (instead of .py), and then put in 192.168.1.113/cgi-bin/date.sh, Chrome just downloads the file on the PC. What am I missing?

Thanks for helping!

mike_p
Posts: 30
Joined: Fri Aug 01, 2014 2:35 pm
Location: Surrey, UK

Re: GPIO through CGI

Sat Jan 10, 2015 7:53 am

azpiuser wrote:Apparently the RPIO does not permit access to GPIO without root access - so a python script writing to GPIO needs to be run as "sudo xyz.py
You need to allow the webserver permission to run programs as if prefixed with sudo.
To do this add the program to 'sudoers', by running visudo.
The line you need to add is

Code: Select all

www-data ALL = NOPASSWD: /path-to-script/xyz.py
(in a normal install of Apache on Raspian the webserver is run as user www-data)

User avatar
iinnovations
Posts: 621
Joined: Thu Jun 06, 2013 5:17 pm

Re: GPIO through CGI

Sat Jan 10, 2015 8:59 am

Don't give www-data root permissions. This is a terrible idea. Use something like wiring pi in your *gi to make it happen.

See here: http://www.cupidcontrols.com/2014/09/di ... -wiringpi/
CuPID Controls :: Open Source browser-based sensor and device control
interfaceinnovations.org/cupidcontrols.html
cupidcontrols.com

mike_p
Posts: 30
Joined: Fri Aug 01, 2014 2:35 pm
Location: Surrey, UK

Re: GPIO through CGI

Sat Jan 10, 2015 9:18 am

iinnovations wrote:This is a terrible idea.
What is wrong with giving www-data permission to run a single script that is entirely under the control of the OP?
Have I missed something?

User avatar
joan
Posts: 14996
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: GPIO through CGI

Sat Jan 10, 2015 10:12 am

Sort of true about needing root access.

However if you run my pigpio daemon it has root access.

You can then control the gpios through the daemon as an ordinary user (from Python, C, the command line etc., etc.)

User avatar
DougieLawson
Posts: 39573
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: GPIO through CGI

Sat Jan 10, 2015 1:10 pm

mike_p wrote:
iinnovations wrote:This is a terrible idea.
What is wrong with giving www-data permission to run a single script that is entirely under the control of the OP?
Have I missed something?
It's another security exposure to a system that already has a bad track record for security exposures.

Joan's pigpiod & pigpio is a much better solution.
Note: Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

Criticising any questions is banned on this forum.

Any DMs sent on Twitter will be answered next month.
All fake doctors are on my foes list.

User avatar
Richard-TX
Posts: 1549
Joined: Tue May 28, 2013 3:24 pm
Location: North Texas

Re: GPIO through CGI

Sat Jan 10, 2015 3:37 pm

WHen it comes to the RPI. cgi, gpio, and root access there are a few options.

1 - make your cgi program suid root. (chown root - chmod 4755)
2 - reduce the permissions on the GPIO interface
3 - let the httpd process run as root.

The best option is likely #2 or #1 assuming that the suid cgi program is written with security in mind.

You may have to write your CGI program in c and compile it before you can get it is run suid root.

sudo is an option as well but given the situation, you might as well just let the httpd process run as root. To allow any account to have password-less access to root is a security hole that no reasonable IT department would permit. It is like assigning multiple passwords to root. Having said that, it is a RPI. Few people really care if the system gets "owned". Toss the SD card and do it again.

I wonder how long it would take a script kiddie to "own" a RPI if it were just placed on the open internet assuming the "pi" passwd was changed.

The life expectancy of MS windows used to be so short that the system would be hacked before the windows install was complete.

Anyone care to try? It would be an interesting experiment.

Personally I give it less than 3 days. Certainly less than a week.
Richard
Doing Unix since 1985.
The 9-25-2013 image of Wheezy can be found at:
http://downloads.raspberrypi.org/raspbian/images/raspbian-2013-09-27/2013-09-25-wheezy-raspbian.zip

azpiuser
Posts: 17
Joined: Sun Jun 09, 2013 9:23 pm

Re: GPIO through CGI

Sat Jan 10, 2015 4:30 pm

Thanks for all the replies. I wish I had limited the scope in my original post :) I think pigpio is the way to go. But, aside from that..

Why does this not work :
  • pi@raspberrypi /var/www $ lt
    total 96
    drwxr-xr-x 2 pi pi 4096 Jan 10 00:20 cgi-bin
Shows that cgi-bin is owned by pi. Inside that, is a script called data.py (also owned by pi) which has this code :

Code: Select all

#!/bin/sh
date >> /tmp/test$$.txt
When run from the command line, it does exactly what is expected - there's a new file called testABCD.txt in /tmp each time. This is an innocuous script.

If I try (from my PC) fetching 192.168.1.114/cgi-bin/garbage, I get 404- not found. If I fetch cgi-bin/date.py, then I don't get an error message, but I don't get a new file in /tmp either. So what's going on?

Even if I change the ownership of cgi-bin to root and also the date.py to root, I still don't get what I expect.

Any thoughts?
Thanks

User avatar
DougieLawson
Posts: 39573
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: GPIO through CGI

Sat Jan 10, 2015 4:44 pm

Your web server runs as uid=www-data gid=www-data

DO NOT move your cgi-bin directory anywhere below your DocumentRoot directory, leave it as /usr/lib/cgi-bin what you've done is open a massive security hole.
Note: Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

Criticising any questions is banned on this forum.

Any DMs sent on Twitter will be answered next month.
All fake doctors are on my foes list.

azpiuser
Posts: 17
Joined: Sun Jun 09, 2013 9:23 pm

Re: GPIO through CGI

Sat Jan 10, 2015 5:04 pm

Okay, a bit of CGI learning, but, basically, it was a settings issue.

Apparently the "#!/script/that/interprets" that you put on the first line of your script does absolutely nothing for lighttpd. You have to change

Code: Select all

$HTTP["url"] =~ "^/cgi-bin/" {
        cgi.assign = ( ".py" => "/usr/bin/python" ,
                        ".pl" => "/usr/bin/perl",
                        ".sh" => "/bin/sh")
}
in the lighttpd.conf (/etc/lighttpd) (Note that default had only .py. If you try a .pl hello-world cgi, you get 403 forbidden if you don't have .pl in the assign list). Once done, the innocuous date.sh (which was previously being downloaded by the browser, now generates 500 - Internal Server Error, but, nevertheless, does that we expect - and creates a new dateABCD.txt file in /tmp.

So, I should be good to go with web control of GPIO once I switch to pigpio from RPIO.

Thanks!

User avatar
rpdom
Posts: 17427
Joined: Sun May 06, 2012 5:17 am
Location: Chelmsford, Essex, UK

Re: GPIO through CGI

Sat Jan 10, 2015 5:24 pm

To find out what the 500 error is about you should check the log file /var/log/apache2/error.log

azpiuser
Posts: 17
Joined: Sun Jun 09, 2013 9:23 pm

Re: GPIO through CGI

Sat Jan 10, 2015 8:30 pm

Any thoughts why this would work perfectly without the call to call?

Code: Select all

#!/usr/bin/python

from subprocess import call

call("echo", shell=False)

print "Content-type: text/html\n\n"
print "<html>Hello world!</html>"
? Without the call, I get my browser showing HW, with the call, I get
  • Content-type: text/html

    <html>Hello world!</html>
That's essentially what's preventing me from writing to GPIO through CGI. Otherwise, pigpio is working fine.

WebPi
Posts: 262
Joined: Wed Apr 10, 2013 6:47 pm
Location: Birmingham, UK
Contact: Website

Re: GPIO through CGI

Sat Jan 10, 2015 8:50 pm

Move the call to 'call' below the line that prints the header. The echo command prints a new line which makes the browser think that the headers have finished early. If you print the header first it should work.
raspberrywebserver.com - Raspberry Pi tutorials
LinuxWebServers.net - Linux Web Server tutorials and examples
pyplate.com - Python web publishing tool

azpiuser
Posts: 17
Joined: Sun Jun 09, 2013 9:23 pm

Re: GPIO through CGI

Sat Jan 10, 2015 8:58 pm

Tried, no luck there either. The difference in output (on the browser) between

Code: Select all

from subprocess import call
print "Content-type: text/html\n\n"
call("echo > /dev/null 2>&1", shell=False)
print "<html>Hello world!</html>"
and

Code: Select all

from subprocess import call
print "Content-type: text/html\n\n"
call("echo", shell=False)
print "<html>Hello world!</html>"
Is that in for former case, I get nothing, and in the latter case, I get the text display of what the script put out (the browser failed to interpret it as HTML and display HW..)

azpiuser
Posts: 17
Joined: Sun Jun 09, 2013 9:23 pm

Re: GPIO through CGI

Sun Jan 11, 2015 6:04 pm

I installed pigpio using the instructions on abyz.co.uk. The procedure is not what I have been used to. I usually do things like

sudo apt-get install xyz
sudo easy_install ...

So I was wondering how we could migrate this library (pigpio) to that install procedure. I'm happy to contribute to make that happen, but don't have the knowhow. I am happy to learn. If you know of a resource that I can refer to, please share.

-rst-
Posts: 1316
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland

Re: GPIO through CGI

Thu Jan 29, 2015 5:02 pm

Did you get the HTML output working?

Wondering if there is difference between:

Code: Select all

print "Content-type: text/html\n\n"
and

Code: Select all

print "Content-type: text/html"
print
https://docs.python.org/2/library/cgi.html
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'

User avatar
DougieLawson
Posts: 39573
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: GPIO through CGI

Thu Jan 29, 2015 5:13 pm

HTTP needs \r\n\r\n (with the emphasis on \r). It doesn't matter which way you create it with one print or two.
Note: Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

Criticising any questions is banned on this forum.

Any DMs sent on Twitter will be answered next month.
All fake doctors are on my foes list.

azpiuser
Posts: 17
Joined: Sun Jun 09, 2013 9:23 pm

Re: GPIO through CGI

Thu Jan 29, 2015 6:05 pm

I gave up on Python and went to Perl and it worked..

#!/usr/bin/perl
print "Content-type: text/html\n\n";
system("/home/pi/projects/pgpio_toggle_17.py");
print "<html>Hello, World!\n</html>";

-rst-
Posts: 1316
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland

Re: GPIO through CGI

Fri Jan 30, 2015 5:22 pm

Good to hear you got it working which is the main goal of course.

For the secondary goal of learning and education...

The HTTP spec does clearly say it has to be CRLF but I found out that either one of these work fine (lighttpd running under cygwin, chrome browser on Windows 7):

Code: Select all

#!/usr/bin/python
print "Content-type: text/html"
print
print "<html>"
print "<head><title>Python test</title></head>"
print "<body>"
print "<H1>Python test</H1>"
print "</body>"
print "</html>"

Code: Select all

#!/usr/bin/python
print "Content-type: text/html\n"
print "<html>"
print "<head><title>Python test</title></head>"
print "<body>"
print "<H1>Python test</H1>"
print "</body>"
print "</html>"

In browser:
Image
Developer tools - headers (note the content type):
Image
Developer tools - response (note the html starts on line 1):
Image

...adding the second '\n' at end of the context type string only adds one more empty line - have to remember that Python print always adds a newline at the end (if not specifically told not to)!

Not sure if the httpd does the LF -> CRLF conversion but as it worked for the OP I assume it does. I even ran the scripts on command line redirecting output to file and checked that there are only LFs in the output:

Image


As it comes to the subprocess.call issue, it appears that the newline created by the echo command gets first into the response output stream - no matter at what point in the script it is! And of course the empty line before the content type gets the browser confused:

Image

This becomes more apparent if we output something other than just the empty line:

Code: Select all

#!/usr/bin/python
from subprocess import call
print "Content-type: text/html"
print
print "<html>"
print "<head><title>Python test</title></head>"
print "<body>"
print "<H1>Python test</H1>"
call(["echo", "testing"], shell=False)
print "</body>"
print "</html>"

...which is equivalent to the shell command 'echo testing' - so using os.system would be:

Code: Select all

#!/usr/bin/python
from os import system
print "Content-type: text/html"
print
print "<html>"
print "<head><title>Python test</title></head>"
print "<body>"
print "<H1>Python test</H1>"
system("echo testing")
print "</body>"
print "</html>"
and produces:
Image

Now if instead of a (by bad luck) pathological test-case with the echo, the OP would have put in the actual call to the GPIO script, it would have worked (assuming the script would not output to stdout == use print() etc.)!

Now it would be interesting to know if the Perl version calling the echo would fail as well?
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'

azpiuser
Posts: 17
Joined: Sun Jun 09, 2013 9:23 pm

Re: GPIO through CGI

Fri Jan 30, 2015 5:45 pm

I have lighttpd on the pi and Chrome on Win 7.

When I do :

Code: Select all

#!/usr/bin/perl

print "Content-type: text/html\n\n";
system("/home/pi/projects/pgpio_toggle_17.py");
system("echo testing");
print "<html>Hello, World!\n</html>";
In /var/www/cgi-bin hw.pl (and of course, the LED toggles)

I get

testing Hello, World!

on the browser..

Ian_Add
Posts: 6
Joined: Wed Feb 04, 2015 3:17 am

Re: GPIO through CGI

Wed Feb 04, 2015 5:25 am

joan wrote:However if you run my pigpio daemon it has root access.

You can then control the gpios through the daemon as an ordinary user (from Python, C, the command line etc., etc.)
I like this idea and have installed your stuff and have got to the point of testing but have a DHT11 not a DHT22.
(I have Adafruit's python examples to work so I know the device is up and running)

I am looking at your DHT22.py example and wondered if merely changing 22 to 11 for the library and the call would do it?

I am guessing that the 22 in the .sensor(pi, 22, LED=16, power =8) is the GPIO pin... Am I right.?

Currently the output with my 22 to 11 changes I am getting:
1 -999 -999 -999 00 0 0 1 0 as the first line of output.

Can someone put me back on track? :)

The objective at the end is to get the live values onto a web page.

Return to “General programming discussion”