Proper method to acquire root access on Linux for Qt applications - c++

Good day
Background:
I am creating an OpenVPN wrapper application for Linux systems which is near completion. I have run into a little snag.
OpenVPN requires root access to modify routing tables (add and remove routes). Here is where things get a little vague and confusing.
Hopefully, by extending this question, some industry standard answers and solutions could be shared.
Documentation:
So, after a number of hours searching, I compiled a list of possible methods for acquiring root access, however none seem to be official nor any real solid guidance given to acquire this SU privilege.
Let us consider the following methods.
1. Using pkexec & polkits
Please find official freedesktop polkit documentation here and here for some information on best practises
There are a few tutorials found online using pkexec and polkits
- here, this helped me create my polkit file.
- SO Thread
- And a lovely small tutorial for Qt applications
To give a brief explanation (of my understanding) about pkexec and polkits:
polkits:
polkits consist of actions and rules (see documenation for indepth reading and explaination). It defines actions of an application and the rules associated with it. Rules can be defined as a user belonging to a specific group, whereby the action queries the rule, it it has succeeded in passing the rule, the user is authenticated automatically (with no popup password prompt), else they are required to enter an administrator password
pkexec:
a application used to interface with the polkit actions and authenticate an application to acquire root access.
These require adding an action into /usr/share/polkit-1/actions/ and /usr/share/polkit-1/rules.d/ (amongst other directories, see documentation for all locations)
This method seems to be well used (but requires a bit more explaination to be understood easily, imo)
note: There are qt-polkit libraries made available for usage, see their github repository
For a simple TL;DR version, see this
The polkit file I created (note this may not be correct, but it does work for me):
Location where it can be found/added (there are others too)
/usr/share/polkit-1/actions
Policy Kit file name:
com.myappname.something.policy // the .policy is required
Note:
com.myappname.something
is refereed to as the namespace of the policy (reading the documenation, this will not be clear)
Policy Kit content
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD polkit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/software/polkit/policyconfig-1.dtd">
<policyconfig>
<vendor>My App Name</vendor>
<vendor_url>http://myappurl.com/</vendor_url>
<action id="com.myappname.something.myaction-name">
<description>Run the polkit for My App which requires it for X usage</description>
<message>My App requires access to X, which requires root authentication, please let me have su access</message>
<icon_name>myappname</icon_name>
<defaults>
<allow_any>auth_admin_keep</allow_any>
<allow_inactive>auth_admin_keep</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/myappname</annotate>
<annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
</action>
</policyconfig>
Notes about my policy file (the important bits)
This is just an example, see documentation for official examples and descriptions:
<vendor>My App Name</vendor> is the application name, it can have spaces
<action id="com.myappname.something.myaction-name"> any action name here.
NOTE!
The file name -> com.myappname.something.policy and,
the action id -> com.myappname.something.myaction-name should have the same namespace
The icon name should be in accordance with with the latest freedesktop icon spec found here
TL;DR (or don't want to):
icon locations are:
1. /home/yourusername/.icons (sometimes not there)
2. /home/yourusername/.local/share/icons
2. /usr/share/icons
as long as they conform to the sizes and are a .png, you can pass the filename only (omitting the format)
Very Important:
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/myappname</annotate>
<annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
When calling pkexec <myappname>, and NOT having these lines (honestly, I am not quite sure purpose of them), one will run into an error similar to this:
2017-12-19 12::58:24 Fatal: QXcbConnection: Could not connect to display ((null):0, (null))
Aborted (core dumped)
Note: keep the key the same, however you can and probably should change the exec.path key to your application location.
How do policy kits work?
In short, if you review the lovely example mentioned earlier (and skip all the very similar names of files), it becomes clear.
When one runs:
pkexec <myappname>
this calls the local authentication agent to run the application (in our case) as root.
This is handled by the actions (the policy kit mentioned above). Further more, the rules utilize the action id to perform addition queries, etc which can be viewed in the provided examples above.
Once the admin password has been entered, depending on the 'settings' entered into defaults (see here), we have:
auth_admin_keep
Like auth_admin but the authorization is kept for a brief period (e.g. five minutes).
Thus, the user can (in my OpenVPN application) connect to an OpenVPN connection for the next 5 minutes, until the password is requested again.
2. Sudo (/etc/sudoers):
This seems to be the go to method for most users who required root access, however it is not recommended:
e.g. Check root access before running the main application by calling a singleShot QProcess with arguments:
/bin/sh -c sudo -v
will result in exit code of 1 in various Linux distributions (thus causing me to search for alternatives)
3. setuid():
A very good example can be found here, unfortunatly it doesn't seem to work on modern Linux distros for the reason of it being a security hole which can easily be exploited.
In short, the process requires one to:
chmod +x <executable>
and checking that the s bit is set in the application using getuid() to get the user id and getgid() to get the group id of the user.
These functions can be found in Linux headers defined by:
<sys/types.h> // defines structs
<unistd.h> // defines methods
However, this does not seem to work with modern day Linux systems. Here is the output of executing a root owned application with the s bit set, run as a normal (unprivileged) user:
2017-12-19 12::21:08 Fatal: FATAL: The application binary appears to be running setuid, this is a security hole. ((null):0, (null))
Aborted (core dumped)
Farewell, setuid()
4. Other methods:
PAM
for further reading, see
man page
tutorial/explanation
A QT Forum question regarding cross platform PAM intergration
QT usermode
Qt provides a small implementation for acquiring root access, but it is only available to Linux distrobutions using yum package manager.
A question followed up on this, see this QT Forum question
Problem:
Above may only include a small portion of available methods to acquire root access, however considering that some applications are used globally, they are often attacked or pried apart or even compromised.
After doing this research, it has broadened my knowledge, but hasn't given me a sure-fire method which is recommended, but only hints.
Question:
Which method above is preferred in industry i.e. when should I use the one over the other (PAM vs polkits vs simple sudo) and if other methods are available, are these preferred?

However, this does not seem to work with modern day Linux systems.
Here is the output of executing a root owned application with the s
bit set, run as a normal (unprivileged) user:
2017-12-19 12::21:08 Fatal: FATAL: The application binary appears to be running setuid, this is a security hole. ((null):0, (null))
The above error has nothing to do with modern day Linux systems. Its a Qt protection against stupid developers using setuid without understanding it.
Simply call
QCoreApplication::setSetuidAllowed(true)
when your application starts, and then you can do setuid() just fine. You can even run privileged commands before dropping down to 'normal' user.
Summary:
Your Qt application must have root owner, and setuid bit set. Example debmaker is my Qt application that I want to perform privileged actions from. So after I build debmaker, I do:
sudo chown root:root debmaker
sudo chmod 4755 debmaker
(The latter sets the setuid bit)
Now run the Qt application
./debmaker
First thing the app does is check geteuid()==0 and getuid()==1000 (1000 is my user id, 0 is the root)
Then it launches a new process (using QProcess in Qt). This will run in privileged mode. (Example my child process is called chroot)
Now drop the main application (my debmaker) to normal user level by calling
setuid(getuid());
chroot (the child process ) will keep running as root user.
The main application, now no longer is running in elevated mode, but can send requests to its child process which is still running in elevated mode.
QProcess *chroot = new QProcess;
blah blah setup the chroot and start it
chroot->write("chown root:root /home/oosman/foo");
The last line will send a message to the child process. You read the stdin in the child process, parse the command, check it to ensure its not malicious (or malicious depending on your intent!) and execute the command.

Good research. But want add new case:
I think better way is make new Unix group and grant write access to target config file for group members. You will just add users to group. And only that users will change routes.
If routes defines with particular program. You can allow to run that program only for group members.

Related

Start/Stop daemon on Linux via C++ code

I am trying to find out a way to launch a custom daemon from my program. The daemon itself is implemented using double-forking mechanism and works fine if launched directly.
So far I have come across various ways to start a daemon:
Create an init script and install it to init.d directory.
Launch the program using start-stop-daemon command.
Create .desktop file and place in one of the autostart paths.
While the 1st 2 methods are known to start the service using command line, the 3rd method is for autostarting the service (or any other application) at user login.
So far my guess is that the program can be executed directly using exec() family of functions, or the 'start-stop-daemon' command can be executed via system() function.
Is there a better way to start/stop service?
Generally startups are done from shell scripts that would call your C++ program which would then do its double fork. Note that it should also close unneeded file descriptors, use setsid() and possibly setpgid/setpgrp (I can't remember if these apply to Linux too), possibly chdir("/"), etc. There are a number of fairly normal things to do which are described in the Stevens book - for more info see http://software.clapper.org/daemonize/daemonize.html
If the daemon is supposed to run with root or other system user account, then the system /etc/init/ or /etc/init.d/ mechanisms are appropriate places to have scripts to stop|start|status|etc your daemon.
If the deamon is supposed to be for the user, and run under his/her account, you have a couple of options.
1) the .desktop file - I'm not personally a fan, but if it also does something for you on logging out (like let you trigger shutting down your daemon), it might be viable.
2) For console logins, the ~/.bash_login and ~/.bash_logout - you can have these run commands supported by your daemon's wrapper to start it and (later) shut it down. The latter can be done by saving the PID in a file or having the .bash_login keep it in a variable the .bash_logout will use later. This may involve some tweaking to make sure the two scripts get run, once each, by the outermost login shell only (normal .bashrc stuff stays in the .bashrc, and .bash_login would need to read it in for the login shell before starting the daemon, so the PATH and so on would be set up by then).
3) For graphic environments, you'd need to find the wrapper script from which things like your X window manager are run. I'm using lightdm, and at some point /etc/X11/Xsession.d/40x11-common_xsessionrc ends up running my ~/.xsessionrc which gives me a hook to startup anything I want (I have it run my ~/.xinitrc which runs my window manager and everything), as well as the place to shot everything down later. The lack of standardization for giving control to the user makes finding the hook pretty annoying, since just using a different login manager (e.g. lightdm versus gdb) can change where the hook is.
4) A completely different approach is to just have the user's crontab start up the daemon. Run "man 5 crontab" and look for the special #reboot option to have tasks run at boot. I haven't used it myself - there's a chance it's root restricted, but it's easy to test and you need only contemplate having your daemon exist gracefully (and quickly) at system shutdown when the system sends it a SIGTERM signal (see /etc/init.d/sendsigs for details).
Hope something from that helps.

When does an application absolutely require to be run as an administrator?

I have been dabbling with working nicely with UAC for a while and I found about a few things:
With UAC enabled, a program in the Startup folder, that requires to be run as admin (say by an embedded manifest), cannot be run according to this Stack Overflow thread.
Another method of running a program at startup is by creating a key containing the path to that application in: HKLM or HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run or HKLM or HKCU\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Run in 64 bit machines.
Yet another method is using the task scheduler setting the Run with highest privileges option. This is the only method that bypasses the problem stated in point 1.
Coming from a Linux background, I had no clue about all these admin rights related problems. If someone can list out scenarios which absolutely need administrator privileges, it would be of great help!
I'm asking this because when I'm developing some application, I keep encountering several problems during implementation mostly because my application required admin rights when it shouldn't.
If I know, at design time, all possible scenarios that require admin rights, I could possibly design a common service for all my applications that takes care of all the administrator tasks (I think services are the Windows way of doing things like this).
There really isn't a list of scenarios or API function calls that require elevation. Your best option will probably be to focus on what API calls require elevation. The reason for this is that it may be required only if certain values are passed to the function. For instance CreateFile can create a file in your home directory without elevation but requires it for creating a file in C:\Windows. If the directory is provided through user input the only way you can know if elevation is required is to check the error code when the call fails. If elevation is required the function will set the error status to ERROR_ACCESS_DENIED and return a value indicating failure.

Catching system events in C Linux

I am writing an application on Linux which requires me to catch system events like:
System reboot
User 'xyz' logs in
'xyz' application crashes etc.
and need to execute some functionality based on that. For e.g.:
Run backup script
Run recovery program etc.
Can anyone please tell me how to catch system events in C/Linux ?
P.S: I am not talking about 'file system' events here :P
There is no concept of "system event". You need to specify which events you need to handle and implement appropriate mechanism for handling each:
System startup: The init process calls scripts from /etc/init.d during startup. The exact infrastructure differs slightly between distributions, but Linux Standards Base System Initialization should generally work on all.
User login/logout: The LSB also defines interface to the Pluggable Authentication Modules library. You can implement a shared library that will be called during login (and also other actions that require authentication and authorization). Depending on what you want to do there may already be a module that will work for you, so try looking for it first. In either case I don't think there is distribution-independent way of installing it and even on given distribution you have to consider that administrator might have made custom modification, so the installation will need manual intervention by the administrator.
Application crashes: You would have to instrument it.
I think you should consider reading systems logs - everything you ask about is logged to the syslog (for standard configuration). If your system uses syslog-ng, then you could even configure it to write directly to your program, see http://www.syslog.org/syslog-ng/v2/#id2536904 for details. But even with any other syslog daemon, you can always read file (or files) from /var/log just like tail -f does, end react on particular messages.
I'm not sure about catching application crashes - there's a kernel option to log every SIGSEGV in user processes, but AFAIK it is available only on ARM architecture - last resort would be to instrument your application (as Jan Hudec pointed out) to log something to syslog.

How do I grant root access to a user application?

I have a user-level C++ test application running on a linux mobile device. One of the test involves enabling/disabling printer paper sensor which requires root privileges writing on a device file. Is there a way to grant my application that kind of privilege? If none, is there a workaround for that?
This will do,
as root execute:
chown -v root:root /path/to/yourapp
chmod -v 4755 /path/to/yourapp
or alternatively
chmod -v u+s /path/to/yourapp
or alternatively
man chmod
This will not work with scripts. And yes, you should take seriously what jdizzle said about dropping unnecessary privileges.
Another way to solve this is to make the user who runs the application a member of the group that owns the device file. For example,
ls -la /dev/devicefile
crw-rw---- 1 root printer 4, 0 may 6 10:56 /dev/devicefile
members of the printer group can read and write to the device, so you just need to add joe to the printer group (and restart the session).
gpasswd -a joe printer
If you need to adjust the devicefile permissions, you probably will need to edit udev rules to make it permanent. But chmod should work too.
Other options worth investigating: setcap(8) (nice guide here) and sudo(8).
You can set the program setuid root, which means it will always run as root even when run by a user. This typically requires special care to drop privileges inside the program once the necessary actions requiring root access are completed.
You could also have a helper program, itself setuid root -or with appropriate capabilities, or started thru sudo- which communicate with the printer. Your main application would fork & exec that program and communicate with it thru pipes, so it should not be itself running as root.
The helper program would be a simple executable (with appropriate capabilities) which would only be started by your main application (not directly by the user) and communicate with it thru pipes or program arguments, etc.
A lot of graphical administrative programs are done likewise: the graphical part is a program separated from the administrative part, and they communicate appropriately. Only the administrative program (usually existing command line programs like adduser) need special privilege.
you should definitey try to avoid running your program as "root", as this would not only allow your program to read/write /dev/sensordevice but it would grant access to virtually everything on your system (including the ability to completely brick it)
you should therefore try to add fine-grained access to just the ressource you need, using proper groups and making sure that your device-file grants your group write access.
see (e.g.) udev on how to write a proper udev rule, that grants write access for a certain device to a given group.

Automatically checking for a new version of my application

Trying to honor a feature request from our customers, I'd like that my application, when Internet is available, check on our website if a new version is available.
The problem is that I have no idea about what have to be done on the server side.
I can imagine that my application (developped in C++ using Qt) has to send a request (HTTP ?) to the server, but what is going to respond to this request ? In order to go through firewalls, I guess I'll have to use port 80 ? Is this correct ?
Or, for such a feature, do I have to ask our network admin to open a specific port number through which I'll communicate ?
#pilif : thanks for your detailed answer. There is still something which is unclear for me :
like
http://www.example.com/update?version=1.2.4
Then you can return what ever you want, probably also the download-URL of the installer of the new version.
How do I return something ? Will it be a php or asp page (I know nothing about PHP nor ASP, I have to confess) ? How can I decode the ?version=1.2.4 part in order to return something accordingly ?
I would absolutely recommend to just do a plain HTTP request to your website. Everything else is bound to fail.
I'd make a HTTP GET request to a certain page on your site containing the version of the local application.
like
http://www.example.com/update?version=1.2.4
Then you can return what ever you want, probably also the download-URL of the installer of the new version.
Why not just put a static file with the latest version to the server and let the client decide? Because you may want (or need) to have control over the process. Maybe 1.2 won't be compatible with the server in the future, so you want the server to force the update to 1.3, but the update from 1.2.4 to 1.2.6 could be uncritical, so you might want to present the client with an optional update.
Or you want to have a breakdown over the installed base.
Or whatever. Usually, I've learned it's best to keep as much intelligence on the server, because the server is what you have ultimate control over.
Speaking here with a bit of experience in the field, here's a small preview of what can (and will - trust me) go wrong:
Your Application will be prevented from making HTTP-Requests by the various Personal Firewall applications out there.
A considerable percentage of users won't have the needed permissions to actually get the update process going.
Even if your users have allowed the old version past their personal firewall, said tool will complain because the .EXE has changed and will recommend the user not to allow the new exe to connect (users usually comply with the wishes of their security tool here).
In managed environments, you'll be shot and hanged (not necessarily in that order) for loading executable content from the web and then actually executing it.
So to keep the damage as low as possible,
fail silently when you can't connect to the update server
before updating, make sure that you have write-permission to the install directory and warn the user if you do not, or just don't update at all.
Provide a way for administrators to turn the auto-update off.
It's no fun to do what you are about to do - especially when you deal with non technically inclined users as I had to numerous times.
Pilif answer was good, and I have lots of experience with this too, but I'd like to add something more:
Remember that if you start yourapp.exe, then the "updater" will try to overwrite yourapp.exe with the newest version. Depending upon your operating system and programming environment (you've mentioned C++/QT, I have no experience with those), you will not be able to overwrite yourapp.exe because it will be in use.
What I have done is create a launcher. I have a MyAppLauncher.exe that uses a config file (xml, very simple) to launch the "real exe". Should a new version exist, the Launcher can update the "real exe" because it's not in use, and then relaunch the new version.
Just keep that in mind and you'll be safe.
Martin,
you are absolutely right of course. But I would deliver the launcher with the installer. Or just download the installer, launch it and quit myself as soon as possible. The reason is bugs in the launcher. You would never, ever, want to be dependent on a component you cannot update (or forget to include in the initial drop).
So the payload I distribute with the updating process of my application is just the standard installer, but devoid of any significant UI. Once the client has checked that the installer has a chance of running successfully and once it has downloaded the updater, it runs that and quits itself.
The updater than runs, installs its payload into the original installation directory and restarts the (hopefully updated) application.
Still: The process is hairy and you better think twice before implementing an Auto Update functionality on the Windows Platform when your application has a wide focus of usage.
in php, the thing is easy:
<?php
if (version_compare($_GET['version'], "1.4.0") < 0){
echo "http://www.example.com/update.exe";
}else{
echo "no update";
}
?>
if course you could extend this so the currently available version isn't hard-coded inside the script, but this is just about illustrating the point.
In your application you would have this pseudo code:
result = makeHTTPRequest("http://www.example.com/update?version=" + getExeVersion());
if result != "no update" then
updater = downloadUpdater(result);
ShellExecute(updater);
ExitApplication;
end;
Feel free to extend the "protocol" by specifying something the PHP script could return to tell the client whether it's an important, mandatory update or not.
Or you can add some text to display to the user - maybe containing some information about what's changed.
Your possibilities are quite limitless.
My Qt app just uses QHttp to read tiny XML file off my website that contains the latest version number. If this is greater than the current version number it gives the option to go to the download page. Very simple. Works fine.
I would agree with #Martin and #Pilif's answer, but add;
Consider allowing your end-users to decide if they want to actually install the update there and then, or delay the installation of the update until they've finished using the program.
I don't know the purpose/function of your app but many applications are launched when the user needs to do something specific there and then - nothing more annoying than launching an app and then being told it's found a new version, and you having to wait for it to download, shut down the app and relaunch itself. If your program has other resources that might be updated (reference files, databases etc) the problem gets worse.
We had an EPOS system running in about 400 shops, and initially we thought it would be great to have the program spot updates and download them (using a file containing a version number very similar to the suggestions you have above)... great idea. Until all of the shops started up their systems at around the same time (8:45-8:50am), and our server was hit serving a 20+Mb download to 400 remote servers, which would then update the local software and cause a restart. Chaos - with nobody able to trade for about 10 minutes.
Needless to say that this caused us to subsequently turn off the 'check for updates' feature and redesign it to allow the shops to 'delay' the update until later in the day. :-)
EDIT: And if anyone from ADOBE is reading - for god's sake why does the damn acrobat reader insist on trying to download updates and crap when I just want to fire-it-up to read a document? Isn't it slow enough at starting, and bloated enough, as it is, without wasting a further 20-30 seconds of my life looking for updates every time I want to read a PDF?
DONT THEY USE THEIR OWN SOFTWARE??!!! :-)
On the server you could just have a simple file "latestversion.txt" which contains the version number (and maybe download URL) of the latest version. The client then just needs to read this file using a simple HTTP request (yes, to port 80) to retrieve http://your.web.site/latestversion.txt, which you can then parse to get the version number. This way you don't need any fancy server code --- you just need to add a simple file to your existing website.
if you keep your files in the update directory on example.com, this PHP script should download them for you given the request previously mentioned. (your update would be yourprogram.1.2.4.exe
$version = $_GET['version'];
$filename = "yourprogram" . $version . ".exe";
$filesize = filesize($filename);
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: post-check=0, pre-check=0");
header("Content-type: application-download");
header('Content-Length: ' . $filesize);
header('Content-Disposition: attachment; filename="' . basename($filename).'"');
header("Content-Transfer-Encoding: binary");
This makes your web browser think it's downloading an application.
The simplest way to make this happen is to fire an HTTP request using a library like libcurl and make it download an ini or xml file which contains the online version and where a new version would be available online.
After parsing the xml file you can determine if a new version is needed and download the new version with libcurl and install it.
Just put an (XML) file on your server with the version number of the latest version, and a URL to the download the new version from. Your application can then request the XML file, look if the version differs from its own, and take action accordingly.
I think that simple XML file on the server would be sufficient for version checking only purposes.
You would need then only an ftp account on your server and build system that is able to send a file via ftp after it has built a new version. That build system could even put installation files/zip on your website directly!
If you want to keep it really basic, simply upload a version.txt to a webserver, that contains an integer version number. Download that check against the latest version.txt you downloaded and then just download the msi or setup package and run it.
More advanced versions would be to use rss, xml or similar. It would be best to use a third-party library to parse the rss and you could include information that is displayed to your user about changes if you wish to do so.
Basically you just need simple download functionality.
Both these solutions will only require you to access port 80 outgoing from the client side. This should normally not require any changes to firewalls or networking (on the client side) and you simply need to have a internet facing web server (web hosting, colocation or your own server - all would work here).
There are a couple of commercial auto-update solutions available. I'll leave the recommendations for those to others answerers, because I only have experience on the .net side with Click-Once and Updater Application Block (the latter is not continued any more).