Jack Bizon Posted March 5, 2016 Posted March 5, 2016 Hi everyone! I was asked by tkaiser to share something about my PHP control of GPIO pins. I can tell you that I will be happy to do so. Mostly because I'm really extremly good in one thing and that is forgetting how i did something. Now let's cut bulls**t down and start with small introduction of what I'm up to. I'll decsribe what I'm doing and what is working for me so it should all click together as project documentation and tutorial. Also all I'm going to describe is being done on Cubieboard2 (A20) but i guess that it can work almost on any ARM SBC running Debian or Ubuntu. Introduction / Motivation Basically, I'm really interested in connecting low-level hardware to high-level software applications. Why? Why throw some rellays on 8-bit atmega, connect the whole contraption to internet and control your lamp from wherever in the world? Well... because we can and also why not! So with this mindset, all that Raspberry Pi hype and working atmega contraption on my table I decided to buy Cubieboard2 back in 2013. Aaaand it was the most stupid thing I could do. Support absolute zero,community non-existent and bootable images were unusable. But it was nice dust collector running Android! Long story short, few weeks ago I came across Armbian, saw how active and supported it is and how it spans over multiple boards. Bingo, this is what I need for doing another cool thing. Standalone internet connected GPIO device that could be used by multiple devices / apps without any special driver or communication protocol and whatever else. Project description Whole idea is that Cubieboard will run webserver with PHP application. This application will provide API that will allow GPIO control using http protocol and GET requests. Security here is not a concern as all of this will be hidden behind NAT in secured private LAN. Preparations Let's assume that you have clean install of Armbian 5.0 with Legacy kernel 3.4.110 running on your A10 or A20 board. Very first thing to do is to decide how many GPIO pins and which one you want to use. Most if not all pins that you have physically availible have more than one function. UART, eMMC, SPI, I2C, LCD and many other connections. Basically you need to look into documentation of your board and check if you can use your chosen pins as GPIO instead of thier original purpose. When you have this solved you need to modify script.bin located in /boot. I will take this short way. Take script.bin, convert it to fex using sunxi-tool bin2fex, add your chosen pins into [gpio_para] section, convert modified fex back into bin, put it back to /boot, reboot board. More about this can be found here. After you prepared your pins in script.bin it's about time to get things rolling. I recommend to run first this two commands if your install is as clean as holy water apt-get update apt-get upgrade Apache and PHP5 installation This is easy step as we do not need any configuration and defaults will do just fine. Execute following command apt-get install apache2 php5 FTP server instalation (optional) This is optional but will help with uploading php files to board. First install ProFTPd as standalone server. apt-get install proftpd Now we need to configure ftp server. I will save you labor, config you need is attached just replace original one in /etc/proftpd/proftpd.conf with it. After you replace config restart proftpd service proftpd restart Next you need to create FTP account that will be used for connection to board via FTP. First lets create group named ftpgroup addgroup ftpgroup Now we add user and add it to the ftpgroup adduser ftpuser -shell /bin/false -home /var/www/html adduser ftpuser ftpgroup And last thing is to make this ftpuser owner of /var/www/html chown -R ftpuser:ftpgroup /var/www/html Done. FTP is working now and you can connect and upload PHP files via Total Commander or similar file manager. Link GPIO to web directory If we want control GPIO from PHP we need to make GPIO accessible from web directory. Therefore we have to create symlink from our web directory to GPIO folder ln -s /sys/class/gpio /var/www/html/gpio Setting permissions Now we need to set permissions to allow our PHP scripts access GPIO in full scale. Let's start with exporting and unexporting pins from PHP. To do so user www-data have to be able to write into /sys/class/gpio/export and /sys/class/gpio/unexport. We can achieve this by making www-data sudoer. Run this command visudo and in section # User priviledge specification add following line under line with root www-data ALL=NOPASSWD: ALL Save and exit. Accessing GPIO pins from PHP Here is example code how to access GPIO pin from PHP. shell_exec("sudo bash -c 'echo 37 > gpio/export'"); shell_exec("sudo bash -c 'echo out > gpio/gpio37/direction'"); shell_exec("sudo bash -c 'echo 1 > gpio/gpio37/value'"); That's all for today. If you are interested I can also write up something about PHP library itself and API possibly too. new_proftpd.zip 2
tkaiser Posted March 6, 2016 Posted March 6, 2016 Security here is not a concern as all of this will be hidden behind NAT in secured private LAN. This is not entirely true since there exist some very nice examples of cross site scripting attacks that work very well in such 'behind NAT in secured private LAN' (a malicious website modifies router settings from within the internal net for example). Best practice therefore should be to separate access by using different browsers for different purposes. Only using a browser to access such internal insecure web apps that has no access to the outside will prevent XSS attacks (yeah, very unlikely that anyone attacks your Cubieboard but at least for routers and other stuff that have a web interface like switches, NAS and so on, this should be a requirement). Apart from that thx for the nice tutorial! It should be noted that the whole thing works not only on A10/A20 but with any board after the GPIO pin mappings have been defined.
Jack Bizon Posted March 6, 2016 Author Posted March 6, 2016 This is not entirely true since there exist some very nice examples of cross site scripting attacks that work very well in such 'behind NAT in secured private LAN' (a malicious website modifies router settings from within the internal net for example). You are totally right but what I ment with that sentence is that cubie will not be accessible from outside world and also that I do not care about security because I know that allowing PHP itself to do sudo is also huge security risk. All this is security bomb and more like proof of concept. Many security aware people maybe will have a bit of hair loss. We could have really deep description about security of this kind of application, but that is different story. Apart from that thx for the nice tutorial! It should be noted that the whole thing works not only on A10/A20 but with any board after the GPIO pin mappings have been defined. I did that... Also all I'm going to describe is being done on Cubieboard2 (A20) but i guess that it can work almost on any ARM SBC running Debian or Ubuntu.
Bernie_O Posted March 7, 2016 Posted March 7, 2016 Hi,idea:1. move the commands for manipulating gpio to a script owned by www-data outside the webroot with chmod 100 (only executable, not readable nor writeable by www-data).2. remove general sudo-privileges for www-data by deleting this (in the 1st post added) line from /etc/sudoers: www-data ALL=NOPASSWD: ALL 3. grant sudo privileges for www-data only for that script by adding this line to /etc/sudoers: www-data localhost = NOPASSWD: /path/outside-webroot/gpio-script.sh 4. in PHP just call the new script via shell_exec: shell_exec("sudo /path/outside-webroot/gpio-script.sh"); The script could be written in a way that different parameters could be passed to it, to have the ability to do different gpio-commands with it.Would that raise security to an acceptable level?Best, Bernie_O Edit: 1. I am not absolutely sure, but I think with my approach it is not necessary to link gpio to web-directory (ln -s /sys/class/gpio /var/www/html/gpio). 2. It might be better to use a relative path in the PHP-command shell_exec();
Jack Bizon Posted March 7, 2016 Author Posted March 7, 2016 Hi Bernie, that is great and secure idea! I thought about it but I'm not a big fan of bash so i discarded this idea before even trying. However your way is seems to be the right and correct way.
vlad Posted March 7, 2016 Posted March 7, 2016 @Jack Bizon you mentioned something about controlling the lamp from the internet, even though this is not you use case, that means your *insert board name here* will be accessible from the internet so i would strongly suggest to implement some sort of authentication even if you are the only user accessing it
Jack Bizon Posted March 7, 2016 Author Posted March 7, 2016 vlad, you are right. Letting anyone mess with API would be silly. But this authentication should be handled in PHP itself. You can bring MySQL, rolling codes, encryption and so on into the game. I see many layers in "Controlling lamp over internet". First is to create connection from App to HW, then create library that handles this connection, after that build app using this library and finally add some sort of authentication.
vlad Posted March 7, 2016 Posted March 7, 2016 totally with PHP - i think a basic authentication would be enough http://php.net/manual/en/features.http-auth.phpbut yeah mysql with cookies/sessions based login could also be used for more security or greater flexibility
Recommended Posts