Accessing the GPIO (of a raspberry pi) without ``sudo`` - linux

This question might not be specific to the raspberry pi, of course. Also, I'm relatively new to Linux.
I want to write a little library (in node.js, if that matters) to access the GPIO of the raspberry pi using the sysfs. However, accessing the sysfs requires sudo access, and that's bad for obvious reasons.
Quick2Wire seems to have a solution, but I want to understand it better and not just blindly use it. They've used C of course, but from what I understand, the code isn't complex, and probably can be pulled off with just bash, even if less elegantly. However, more than anything, I'm not sure why it works.
Any help will be great.
Edit: Thanks for the comments. It's clear I need to rephrase the question. Here goes:
How is it that once installed (as root), the app doesn't require any more root perms to use? How does adding someone to a group help in this case? /sys/devices/virtual/gpio isn't the location where the gpio sysfs is available, so what's the trickery with that? I'm really a n00b, so these questions might be n00b-ish, so please bear with me.

Rakesh, I've just been trying to figure out exactly the same thing, and I think I've solved it.
You don't need to understand much of the makefile at all. The important lines are the following, which are executed in bash when you run sudo make install
install: install-files
groupadd -f --system gpio
chgrp gpio $(DESTDIR)/bin/gpio-admin
chmod u=rwxs,g=rx,o= $(DESTDIR)/bin/gpio-admin
groupadd -f --system gpio creates a system group called gpio. chgrp gpio $(DESTDIR)/bin/gpio-admin changes the group of the binary (which the C file gpio-admin.c was compiled to) to gpio. The owner of the binary is still root (since you're running make as root.) chmod u=rwxs,g=rx,o= $(DESTDIR)/bin/gpio-admin does two important things. Firstly, it lets a member of the gpio group run gpio-admin. Secondly, it sets the setuid bit on gpio-admin.
When you add yourself to the gpio group, you can run gpio-admin, without using sudo, but gpio admin will act like it is being run under sudo. This allows it to write to the /sys/class/gpio/export file. It also allows it to change the owner of the files /sys/class/gpio/gpio[pin number]/direction etc. that get created.
Even if you change the group of /sys/class/gpio/export to gpio, and set permissions to allow you to write to it
sudo chgrp gpio /sys/class/gpio/export /sys/class/gpio/unexport
sudo chmod g+rwx /sys/class/gpio/export /sys/class/gpio/unexport
you can export a pin without superuser powers
echo 22 > /sys/class/gpio/export
but the files /sys/class/gpio/gpio22/direction etc. will still be create with root as the owner and group, and you'll need to use sudo to change them. Also, ownership of the export and unexport files will revert to root after each reboot.

Related

/dev/ttyACM0 access denied on Lubuntu boot, but works any other time

I am trying to launch a program on Lubuntu 19.04 that talks to my Arduino Due device (robotics) via serial with /dev/ttyACM0. Everything seems fine, until I try to launch the app at startup.
The problem occurs only when I try to make my app boot at login. Running it as user, from terminal, from .desktop file, from script etc. is not a problem at all, I am able to establish connection 10/10 times.
Please bear in mind that I am putting $USER manually now, in every command it is explicitly passed as my de facto username.
It shouldn't be a permissions problem.
$ ls -la /dev/
...
crw-rw-rw- 1 root dialout 166, 0 mar 13 17:27 ttyACM0
...
$ groups $USER
$USER : $USER root adm tty dialout cdrom sudo dip plugdev lpadmin sambashare
I have tried runing it from .xsessionrc with:
#!/bin/bash
# Some other commands to set the environment up
/home/$USER/user_panel /dev/ttyACM0
I have also tried setting it in LXQt Session Settings with Autostart so i ended up with a .desktop entry:
$ cat ./.config/autostart/$USER\ User\ Panel.desktop
[Desktop Entry]
Exec=/home/$USER/user_panel /dev/ttyACM0
Name=User Panel
Type=Application
Version=1.0
I have tried launching both of that files manually and it was alright, the app started, the connection was made.
I have also tried making my udev rule.
$ cat /etc/udev/rules.d/50-myusb.rules
KERNEL=="ttyACM[0-9]*", MODE="0666
Hence, my question is: what should I look for as the reason for this boot time denial?
I don't know if this is the same problem but I was getting "access denied" when opening /dev/ttyACM0 during a hot-boot of the USB connection. I went through permissions, overrode the kernel to give me ownership of the device and still got the same error. Unless I was debugging, in which case access was fine.
The problem seemed to be that the device had not yet started up and putting a half second delay (you may have to increase it to find what works) was enough to allow the device to initialize and be accessed correctly. Try putting a short delay inside a finite loop while you try to open it.
Hope this helps.

At boot in kubuntu open a shell and run a script

I everybody
after boot if is possible i want to open a shell and run a simple c++ program automatically ! its difficult ?
airone#airone:~$ sudo ./provaccc
[sudo] password for airone:
Reading From : /dev/input/event2 (Sycreader RFID Technology Co., Ltd SYC ID&IC USB Reader)
Ingresso Palestra: SUCCESS
its possible ?
thanks a lot
Well, you can always include it in some of the common "starters", most probably in ~/.bashrc. The one single important thing would be to suppress the stdout prior to putting it over there. You have to adjust its permissions as well, in order not to be asked for the sudo password. With the limited information I have, I presume it should be something like:
chown <user>:<group> airone
chmod 755 provaccc
echo 'bash <full path>/provaccc' > /dev/null >> ~./bashrc
Test it with sourcing ~/.bashrc:
source ~/.bashrc
Of course there could be multiple adjustments, but I am sure you can work these out.

How to change tty group on Linux (build with buildroot)

I'm working on Linux Kernel 3.14.28 build with Buildroot for an embedded device.
In /dev/, all ttys are root:root and not root:dialout like a standard Linux. So it is not possible to access any ttyX without being logged as root.
How can I change the tty group permanently to root:dialout? I try to change it with chown command, but it became root:root again on reboot.
TL;DR: choose mdev as your device manager, and use the tty group instead of dialout.
The kernel's devtmpfs creates device nodes with a default name, owner and permissions. It also sends out a uevent when the node is created, which allows a uevent handler to change the name, ownership or permissions, or do anything else it wants. Previously this was called the hotplug system, but nowadays it's much more generic.
Buildroot offers the choice between three uevent handlers: mdev, which is part of busybox, eudev which is a standalone udev fork, and udev which is part of the systemd init system. These handlers are configured with rules files that specify what to do with a specific type of device when it appears.
For your specific need, mdev is the best choice since it is very simple, easy to understand, doesn't take up much space, and the default configuration is sufficient. In Buildroot's menuconfig, go to System configuration → /dev management and select Dynamic using mdev. Then rebuild your root filesystem. It will now be populated with the mdev binary (part of busybox), an init script to start it, and a default rules file in /etc/mdev.conf. This default file contains:
tty[0-9]* root:tty 660
This means that the tty devices will get their group changed to tty and their permissions to group read and write. So you can just make sure that the logged in user belongs to the tty group, and Bob's your uncle.
If the default mdev.conf file is not sufficient for you (for instance, if you really need the group to be dialout), then you can create a filesystem overlay, copy package/busybox/mdev.conf to /etc/mdev.conf and modify it as needed. Full documentation on the mdev.conf format can be found in the busybox sources.
devtmpfs always sets permissions to 0600 and makes it up to udev (or whatever runs after it) to maintain them. Its source confirms there's no way to override this explicitly (tty device driver overrides mode unconditionally in some cases).
Assuming you're using the Buildroot's default busybox as init, there's a way to do this with the following additional line in busybox's inittab (additional=must be present in addition to the essential lines (or their replacements) that are implied when there's no inittab - as they are no longer implied then there is):
::sysinit:<path_to_your_script>
with the script calling chown and chmod in loop.
But, it's better to handle this within the existing /etc/init.d/rcS (which is also run by BusyBox's init at sysinit by default).
As you can see from the stock buildroot's /etc/init.d/rcS, all you need to do is create a script /etc/init.d/S<whatever>.sh (where "whatever" places it into the desired position in the /etc/init.d/S??* output) with your commands:
for tty in /dev/tty*; do
chown root:dialout "$tty"
chmod ug+rw "$tty" #do not touch other bits
done
unset tty

running shell script on low privileged user

I have a requirement to run a java jar on a low privilege user on linux.
e.g. If I am currently logged in as a 'root' user and want to execute a shell script that should run with the privileges of a low privileged linux user like 'postix' user account.
Is it possible?
If yes, please post relevant references as I don't know how to do it.
Thanks in advance
Ashish
you can use the sudo command to run the script as another user.
If its set up properly, you can use it like this
sudo -u andrew myprog
will run myprog as the user andrew
Not sure what you mean by priority. If you think about scheduling priority, you can use the nice command to run the script with low priority on the CPU. Being logged as 'root' does not give any scheduling priority.
Besides this, it is always a bad idea to be logged in as 'root'.
I think sudo should do the trick .
You can also create script that will run your app change its owner and set suid bit for it
useful commands: chmode, chown

Best practice to run Linux service as a different user

Services default to starting as root at boot time on my RHEL box. If I recall correctly, the same is true for other Linux distros which use the init scripts in /etc/init.d.
What do you think is the best way to instead have the processes run as a (static) user of my choosing?
The only method I'd arrived at was to use something like:
su my_user -c 'daemon my_cmd &>/dev/null &'
But this seems a bit untidy...
Is there some bit of magic tucked away that provides an easy mechanism to automatically start services as other, non-root users?
EDIT: I should have said that the processes I'm starting in this instance are either Python scripts or Java programs. I'd rather not write a native wrapper around them, so unfortunately I'm unable to call setuid() as Black suggests.
On Debian we use the start-stop-daemon utility, which handles pid-files, changing the user, putting the daemon into background and much more.
I'm not familiar with RedHat, but the daemon utility that you are already using (which is defined in /etc/init.d/functions, btw.) is mentioned everywhere as the equivalent to start-stop-daemon, so either it can also change the uid of your program, or the way you do it is already the correct one.
If you look around the net, there are several ready-made wrappers that you can use. Some may even be already packaged in RedHat. Have a look at daemonize, for example.
After looking at all the suggestions here, I've discovered a few things which I hope will be useful to others in my position:
hop is right to point me back
at /etc/init.d/functions: the
daemon function already allows you
to set an alternate user:
daemon --user=my_user my_cmd &>/dev/null &
This is implemented by wrapping the
process invocation with runuser -
more on this later.
Jonathan Leffler is right:
there is setuid in Python:
import os
os.setuid(501) # UID of my_user is 501
I still don't think you can setuid
from inside a JVM, however.
Neither su nor runuser
gracefully handle the case where you
ask to run a command as the user you
already are. E.g.:
[my_user#my_host]$ id
uid=500(my_user) gid=500(my_user) groups=500(my_user)
[my_user#my_host]$ su my_user -c "id"
Password: # don't want to be prompted!
uid=500(my_user) gid=500(my_user) groups=500(my_user)
To workaround that behaviour of su and runuser, I've changed my init script to something like:
if [[ "$USER" == "my_user" ]]
then
daemon my_cmd &>/dev/null &
else
daemon --user=my_user my_cmd &>/dev/null &
fi
Thanks all for your help!
Some daemons (e.g. apache) do this by themselves by calling setuid()
You could use the setuid-file flag to run the process as a different user.
Of course, the solution you mentioned works as well.
If you intend to write your own daemon, then I recommend calling setuid().
This way, your process can
Make use of its root privileges (e.g. open log files, create pid files).
Drop its root privileges at a certain point during startup.
Just to add some other things to watch out for:
Sudo in a init.d script is no good since it needs a tty ("sudo: sorry, you must have a tty to run sudo")
If you are daemonizing a java application, you might want to consider Java Service Wrapper (which provides a mechanism for setting the user id)
Another alternative could be su --session-command=[cmd] [user]
on a CENTOS (Red Hat) virtual machine for svn server:
edited /etc/init.d/svnserver
to change the pid to something that svn can write:
pidfile=${PIDFILE-/home/svn/run/svnserve.pid}
and added option --user=svn:
daemon --pidfile=${pidfile} --user=svn $exec $args
The original pidfile was /var/run/svnserve.pid. The daemon did not start becaseu only root could write there.
These all work:
/etc/init.d/svnserve start
/etc/init.d/svnserve stop
/etc/init.d/svnserve restart
Some things to watch out for:
As you mentioned, su will prompt for a password if you are already the target user
Similarly, setuid(2) will fail if you are already the target user (on some OSs)
setuid(2) does not install privileges or resource controls defined in /etc/limits.conf (Linux) or /etc/user_attr (Solaris)
If you go the setgid(2)/setuid(2) route, don't forget to call initgroups(3) -- more on this here
I generally use /sbin/su to switch to the appropriate user before starting daemons.
Why not try the following in the init script:
setuid $USER application_name
It worked for me.
I needed to run a Spring .jar application as a service, and found a simple way to run this as a specific user:
I changed the owner and group of my jar file to the user I wanted to run as.
Then symlinked this jar in init.d and started the service.
So:
#chown myuser:myuser /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar
#ln -s /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar /etc/init.d/springApp
#service springApp start
#ps aux | grep java
myuser 9970 5.0 9.9 4071348 386132 ? Sl 09:38 0:21 /bin/java -Dsun.misc.URLClassPath.disableJarChecking=true -jar /var/lib/jenkins/workspace/springApp/target/springApp-1.0.jar

Resources