Qt, Linux, check if a given user has sudo privileges
I am running Fedora 17 KDE x64 and Qt 4.8.1.
In contrast with Ubuntu, Fedora doesn't give the first created user sudo privileges - doesn't add the first created user to the "/etc/sudoers" file. Therefore when installing programs on Fedora 17 KDE (haven't tested the Gnome and etc. spins) it requires "root" (not "sudo") privileges. So, we have three levels of privileges (listed in descending order according to the level of privileges):
In Fedora 17 KDE if you have access to the "root" user account you can give "sudo" privileges to any other user you want simply by editing the "/etc/sudoers" file and adding the line:
user ALL = (ALL) ALL
... below the line:
root ALL = (ALL) ALL
Replace "user" with the name of the account you wish to give sudo access to.
But not every user has access to the "root" user's account. That's why the "root" user could give super-user ("sudo") privileges to some user accounts.
What I want to to is to check if the current user running the application is registered as super-user. If so I will make the "/usr/bin/kdesu" tool use the "/usr/bin/sudo" tool which asks for "sudo" password.
If the user is not super-user I leave "/usr/bin/kdesu" behave as it does by default - it uses the "/usr/bin/su" tool that requires "root" password.
Currently, I am using getenv("USER") ("USERNAME" on Windows but I need this functionality on Linux only) to get the current user. The current user's name could be acquired by traversing QProcess::systemEnvironment() where HOSTNAME and USER variables are listed.
Parsing the "/etc/sudoers" file is not an option since opening the file requires "sudo" or "root" privileges.
All this is highly distribution specific: Some don't even use sudo at all!
Usually the users that are allowed to sudo are managed by having them in a group (wheel, admin, depends a lot on the distribution). So you could check which groups the user belongs to.
The best thing to can do is most likely to implement a heuristic for some well known distributions and just ask the user what to do for all others.
Alternatively you could try to avoid the need for root. Some tasks can actually be handled using capabilities instead of full root, some by having a daemon running (or starting it via dbus or something) that your UI connects to. Maybe you could depend on polkit for the privileged task. This of course depends a lot on what you actually want to do.
What I actually want to to is:
- create directory in "/etc" - for example "/etc/my"
- copy a file to "/etc/my"
The distributions that should be supported are Ubuntu and Fedora - both Gnome(Unity) and KDE editions.
On Ubuntu Gnome(Unity), the "/usr/bin/gksu" command is using the "/usr/bin/sudo" (not "/usr/bin/su") command by default e.g. super-user privileges are required by default, not root ones.
On Fedora KDE the "/usr/bin/kdesu" is the "gksu" equivalent for filling the root/sudo password in a graphic manner. Here, the graphical "/usr/bin/kdesu" uses the terminal "/usr/bin/su" program. "su" requires root privileges by default.
But the user is not expected to know the root password. The current user, that executes the given program that copies some files to "/etc/", might just be given sudo privileges by the root user.
So, I want to check whether the current user has been given sudo privileges (by the root user or another sudo user). If so I will run the following terminal commands through a QProcess:
Check to see which terminal command is used by "kdesu":
kreadconfig --file kdesurc --group super-user-command --key super-user-command
If it utilizes "su" I will first make the kdesu use "sudo" so that to ask for the sudo password for the current user if it is a sudo user(that is what I want to check):
kwriteconfig --file kdesurc --group super-user-command --key super-user-command sudo
Then create the directory under "/etc":
kdesu -c "mkdir -p /etc/my"
kdesu -c "cp ~/some_file /etc/my"
Rollback the changes to the command being used by kdesu if such have been introduced:
kwriteconfig --file kdesurc --group super-user-command --key super-user-command su
Sorry, you are mistaken there: There is just root, no super-user. Both su as well as sudo temporarily change your user id to that of root (0). Only root can edit the sudoers file, so only he can allow other users to run sudo.
The first step is possible. You can find out which command kdesu will run. That will of course not work on fedora which uses a different graphical frontend to su/sudo.
The second step makes no sense: If kdesu is configured to use su, then that is usually done for a good reason. This reason could be that sudo is not installed.
Even if sudo is available: There is no way to add a user to the sudoers file that does not require root priviledges. If you find one, then you found a way to exploit linux systems! Once you got root to change the sudoers file you could just as well copy your files.
My point by saying that there is a root user and super-users, is the following:
- Imagine that 2+ persons are using a single PC.
- Only 1 of them knows the root password.
- One of the other people wants to put some files in "/etc/", "/usr/bin", "/usr/lib", "/usr/share". Therefore he/she needs:
a) either to know the root password
... or ...
b) to be added as super-user by the root user
- The person that has created the root account doesn't wan't to share the root account's credentials with the other people. Therefore he/she elevates the privileges of the user in point 3) to super-user privileges. This user is now a super-user but he doesn't know the root account's password (data hiding principle in OOP).
Therefore in my application all I want is to figure out whether the current user has been given super-user privileges for the commands "mkdir" and "cp".
Sorry, but this separation makes no sense. Root has a user id of 0. Any user running sudo has his user id temparary set to 0, too. So he is root for as long as he is running the application he started via sudo and can do anything that root can do with this application. You can limit the commands a user can run via sudo. That makes it a harder to abuse, but this protection is rather weak in general and hard to get right. There are millions of ways to get a shell via many of the normal programs you run or by putting/changing files in /etc, /usr/bin, /usr/lib:-). Once you have a shell you can change the root password, extract the password hashes (to crack them, gaining access to other accounts), manipulate the login system to steal passwords, update the sudoers file, create a root shell for yourself and break the system in any way you want. In your definition: super-user + a bit of work == root.
If you don't trust somebody with the root password, then you can not trust them with an entry in the sudoers file either.
There are some advantages to using sudo/su: It allows for some logging of who actually got root at which time (like "user a logged in and then became root" instead of "root logged in"), but that only works for as long as everybody plays along.
The other advantage of sudo is that it allows you to not have a root password at all. This can be good since the root user can not directly log in that way, making it useless for somebody to try breaking into the root account by guessing the password. Just check the auth logs of any machine on the internet that allows remote logins and you will see that many people are actually trying to do exactly that.
Back to your problem: You could have /etc/mydirectory with some simple configuration installed as part of the package. You could then create a new group and allow anybody in that group to manipulate the configuration file. Then you only have to assign the allowed users to that group and they can manage the configuration without being able to meddle with anything else.
I see. Thank you for the thorough explanation on the case.
As a final, I want my application to do the following:
- Run my application not as super-user(root) but as ordinary user.
- Then by clicking a button in the application's user interface I want to write some files to:
"/etc/<Company Name>/<Application Name>/"
Since the program is started in non-sudo(root) mode, this operation will require additional privileges.
I don't want to ask the current user for the root password but for the sudo password if the current user has been given sudo privileges - this is the only behavior I want to achive.
What is your best proposal for solving the case?
Is this logic correct to your opinion?
I'd suggest using group permissions on the directories/files that the users are supposed to edit and then have the required user assigned into that group. That way you do not need to raise privileges at all to edit the files.
You could also have a daemon that the users contact (via network, sockets, dbus, whatever) that handles authentication, validates the input and then puts it into the right place. Again you could have the user running with reduced privileges or as root. Chances are that you are configuring a system wide service anyway (why else would you want to store settings in /etc?), so maybe that could just take over the configuration changes as well.
I would definitely use file permissions before I tried using sudo. To allow copying arbitrary files into arbitrary location the will essentially need to be able to run a shell of some sort: essentially they are root while this shell runs.
You can see what sudo, if present, will allow the current user to run and whether a password is required using the:
User chrisw may run the following commands on this host:
(ALL) NOPASSWD: /usr/bin/tail -f /var/log/messages
Perhaps that is in some way useful.
@ChrisW67: I have tried this solution already. Calling sudo -l requests for sudo password.