How to programmatically gain root privileges? - c++

I am writing some software (in C++, for Linux/Mac OSX) which runs as a non-privileged user but needs root privileges at some point (to create a new virtual device).
Running this program as root is not a option (mainly for security issues) and I need to know the identity (uid) of the "real" user.
Is there a way to mimic the "sudo" command behavior (ask for user password) to temporarily gain root privileges and perform the particular task ? If so, which functions would I use ?
Thank you very much for your help !

If you need root privileges every time, the best thing is to start your program as root and drop them (in a subprocess) with setuid and setgid. That's what apache does when it needs to bind to the restricted port 80.
If gaining root rights is the exception instead of the rule and the program is run interactively, another way is to write a program add_interface and execute
sudo add_interface args
and let sudo handle authentication for you. Instead of sudo, you may want to use a graphical frontend like gksu, gksudo, kdesu, or kdesudo. I wouldn't try to implement secure password input myself; it can be a tricky problem and you'll probably leave gaping security holes and functionality problems (Do you support fingerprint readers?).
Another alternative is polkit, previously called PolicyKit.

Original answer
You might consider the setuid switch on the executable itself. Wikipedia has an article on it which even shows you the difference between geteuid() and getuid() quite effectively, the former being for finding out who you're "emulating" and the latter for who you "are". The sudo process, for example, geteuid should return 0 (root) and getuid your user's id, however, its sub-processes do truly run as root (you can verify this with sudo id -u -r).
I don't think there's a way to easily programmatically gain root access - after all, applying the principle of least privilege, why would you need to? Common practise is to run only limited parts of code with elevated privileges. A lot of daemons etc are also set up under modern systems to run as their own user with most of the privileges they need. It's only for very specific operations (mounting etc) that root privileges are truly needed.
2013 update
My original answer stands (although my 2013 self might make a better job of it than my 2010 one), but if you are designing an application that requires root access, you may want to consider exactly what sort of root access is needed and consider the use of POSIX Capabilities (man page). These are different to capability-based security as implemented in L4 et al. POSIX capabilities allow your application to be granted a subset of root's powers. For example CAP_SYS_MODULE will allow you to insert kernel modules, but give you no other root powers. This is in use in distributions e.g. Fedora has a feature to completely remove setuid binaries with indiscriminate root access.
This matters because as a programmer, your code is obviously perfect! But, the libraries on which you depend (sigh, if only you'd written them!) might have vulnerabilities in them. Using capabilities, you can limit the use of this exploit, and save yourself and your company from security-related scrutiny. This makes everyone happier.

You can't gain root privileges, you must start out with them and reduce your privileges as needed. The usual way that you do this is to install the program with the "setuid" bit set: this runs the program with the effective userid of the file owner. If you run ls -l on sudo, you'll see that it is installed that way:
-rwsr-xr-x 2 root root 123504 2010-02-25 18:22 /usr/bin/sudo
While your program is running with root privileges, you can call the setuid(2) system call to change your effective userid to some non-privileged user. I believe (but haven't tried this) that you could install your program as root with the setuid bit on, immediately reduce privilege, and then restore privilege as needed (it's possible, however, that once you lower your privilege you won't be able to restore it).
A better solution is to break out the piece of your program that needs to run as root, and install it with the setuid bit turned on. You will, of course, need to take reasonable precautions that it can't be invoked outside of your master program.

Normally this is done by making your binary suid-root.
One way of managing this so that attacks against your program are hard is to minimize the code that runs as root like so:
int privileged_server(int argc, char **argv);
int unprivileged_client(int argc, char **argv, int comlink);
int main(int argc, char **argv) {
int sockets[2];
pid_t child;
socketpair(AF_INET, SOCK_STREAM, 0); /* or is it AF_UNIX? */
child = fork();
if (child < 0) {
perror("fork");
exit(3);
} elseif (child == 0) {
close(sockets[0]);
dup2(sockets[1], 0);
close(sockets[1]);
dup2(0, 1);
dup2(0, 2); /* or not */
_exit(privileged_server(argc, argv));
} else {
close(sockets[1]);
int rtn;
setuid(getuid());
rtn = unprivileged_client(argc, argv, sockets[0]);
wait(child);
return rtn;
}
}
Now the unprivileged code talks to the privileged code via the fd comlink (which is a connected socket). The corresponding privileged code uses stdin/stdout as its end of the comlink.
The privileged code needs to verify the security of every operation it needs to do but as this code is small compared to the unprivileged code this should be reasonably easy.

You might want to take a look at these APIs:
setuid, seteuid, setgid, setegid, ...
They're defined in the header <unistd.h> in Linux systems (don't know much about MAC, but you should have a similar header there too).
One problem that I can see is that the process must have sufficient privileges to change its user-/group- IDs. Otherwise calls to the above functions will result in an error with errorno set to EPERM.
I would suggest that you run your program as the root user, change effective user ID (using seteuid) to an underprivileged user at the very beginning. Then, whenever you need to elevate permissions, prompt for a password then use seteuid again to revert to the root user.

On OS X, you can use the AuthorizationExecuteWithPrivileges function. The page on Authorization Services Tasks has some elaborate discussion of this (and related) functions.
Here's a bit of C++ code to execute a program with administrator privileges:
static bool execute(const std::string &program, const std::vector<std::string> &arguments)
{
AuthorizationRef ref;
if (AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &ref) != errAuthorizationSuccess) {
return false;
}
AuthorizationItem item = {
kAuthorizationRightExecute, 0, 0, 0
};
AuthorizationRights rights = { 1, &item };
const AuthorizationFlags flags = kAuthorizationFlagDefaults
| kAuthorizationFlagInteractionAllowed
| kAuthorizationFlagPreAuthorize
| kAuthorizationFlagExtendRights;
if (AuthorizationCopyRights(ref, &rights, kAuthorizationEmptyEnvironment, flags, 0) != errAuthorizationSuccess) {
AuthorizationFree(ref, kAuthorizationFlagDestroyRights);
return false;
}
std::vector<char*> args;
for (std::vector<std::string>::const_iterator it = arguments.begin(); it != arguments.end(); ++it) {
args.push_back(it->c_str());
}
args.push_back(0);
OSStatus status = AuthorizationExecuteWithPrivileges(ref, program.c_str(), kAuthorizationFlagDefaults, &args[0], 0);
AuthorizationFree(ref, kAuthorizationFlagDestroyRights);
return status == errAuthorizationSuccess;
}

You can try launching the command to create the virtual device (including sudo) through a background shell. Ask for the users password in a dialog of your own and pipe that into the shell when sudo asks for it. There are other solutions like using gksu, but those are not guaranteed to be available on every machine.
You don't run your entire program as root, but only the small part of it that needs root. You should spawn a separate process for that and sudo may be of assistance to you.

Related

C++ how can I add a linux user to a group programatically

is it possible to add a user on Linux to a group, programatically when I start my program? I am using C++. I know it can be done with the shell, but I need to do it in my C++ program, however I don't know what to use.
You could take 2 approaches:
Use the system() call to execute a shell command to do the work.
Directly modify the /etc/group file. It should be fairly easy to locate the line that contains the group you wish to add to, and then append the user you want to add on the end (making sure to add a comma if there's already a group member).
Given the choice, I'd probably use the first option from the above.
EDIT: As #DevSolar pointed out in his comment, this answer is assuming that your system is using standard local authentication using passwd/shadow/group files in /etc. If your system is NOT using local auth, then that's a completely different ballgame.
Jared Sutton's two options are valid, but I'd like to point out that you don't have to implement editing /etc/group yourself if you use an existing library.
I know of at least busybox, which has implemented this. There's a function defined in libbb/update_passwd.c
int update_passwd(const char *filename, // /etc/group
const char *name, // username
const char *new_passwd, // nullptr
const char *member) // groupname
If you do want to implement it yourself, then you can check out how their function works.
This task is solved by many configuration management software. For example in Salt:
def adduser(name, username):
on_redhat_5 = __grains__.get('os_family') == 'RedHat' and __grains__.get('osmajorrelease') == '5'
if __grains__['kernel'] == 'Linux':
if on_redhat_5:
cmd = 'gpasswd -a {0} {1}'.format(username, name)
else:
cmd = 'gpasswd --add {0} {1}'.format(username, name)
else:
cmd = 'usermod -G {0} {1}'.format(name, username)
retcode = __salt__['cmd.retcode'](cmd, python_shell=False)
return not retcode
As you can see, operating system commands are used. Which one depends on what operating system it is :)

detecting if program is installed on machine

Say I have an application I write, that relies for some task on an externat app (lets call it "tool") that is installed on my machine. In my program, I call it with system( "tool myarguments" ); , works fine.
Now, I want to distribute my app. Of course, the end-user might not have "tool" installed on his machine, so I would like my app to check this, and printout a message for the user. So my question is:
Is there a portable way to check for the existence of an app on the machine? (assuming we know its name and it is accessible through the machine's shell).
Additional information: First idea was to check the existence of the binary file, but:
This is platform dependent,
depending on how it has been installed (build from sources, installed through package,...), it might not always be in the same place, although it can be accessed through local path.
My first opinion on this question is "No", but maybe somebody has an idea ?
Reference: system()
Related: stackoverflow.com/questions/7045879
If you use the Qt toolkit, QProcess may help you.
Edit: and look for QProcess::error() return value: if it is QProcess::FailedToStart , then either it is not installed, or you have insufficient permissions.
If running the tool without argument has no side-effect, and is expected to return an exit code of 0, you can use system("tool") to check tool's existence.
You can check whether the command has been found by checking system's return value like this:
int ret = system("tool");
if (ret != 0) {
std::cout << "tool is not here, move along\n";
}
It is portable in the sense that system is expected to return 0 if all goes well and the command return status is 0 too.
For example, on Linux, running system("non_existing_command") returns 0x7F00 (same type of value as returned by wait()).
On Windows, it returns 1 instead.

Permission issue getting uptime with performance counters

I'm trying to read the system uptime using performance counters in C++. I want to support both XP and Windows 7 at minimum.
The following code works fine on Windows XP...
HQUERY hQuery; HCOUNTER hCounter;
PDH_FMT_COUNTERVALUE Value;
int ret = 0;
if (PdhOpenQuery(NULL, 0, &hQuery) == ERROR_SUCCESS) {
if ((status = PdhAddCounter(hQuery, queryURI, 0, &hCounter)) == ERROR_SUCCESS) {
if ((status = PdhCollectQueryData(hQuery)) == ERROR_SUCCESS) {
if ((status = PdhGetFormattedCounterValue(hCounter, PDH_FMT_LARGE, NULL, &Value)) == ERROR_SUCCESS) {
ret = (DWORD)(Value.largeValue);
}
}
PdhRemoveCounter(hCounter);
}
PdhCloseQuery(hQuery);
}
return ret;
..but it fails on Windows 7. Specifically, PdhCollectQueryData returns PDH_NO_DATA regardless of whether or not i run as administrator.
How can i get the system uptime on both Windows 7 and XP? I expect the times to be much larger than the 49-day overflow of GetTickCount, and i would rather not have separate PDH versions for XP and GetTickCount64 versions for 7 if at all possible...
So the help for PdhCollectQueryData indicates that PDH_NO_DATA can be returned if the process doing the query lacks the appropriate elevated token to allow the query. See if you can check exactly what user permissions the process itself has been allocated, regardless of whether you are logged in as admin or not. Windows 7 has a lot of granularity to this concept, especially with UAC turned on. There can be a distinction also between the local Administrator account created with the OS & a member of the Administrators group in terms of what permissions the account ends up with, though I've not encountered a specific one on performance counters.
Try an explicit 'Run as administrator' on the process, for example, and ensure the administrator account you're using really does have that permission (I'm not sure from your question whether you have already tried this or not). Try a user account in the Performance Logs User Group. Try the account that was created when the OS was installed. Try with UAC off. These hopefully should help nail down the source of the problem.
From the Microsoft help on the subject:
Only the administrator of the computer or users in the Performance Logs User Group can log and view counter data. Users in the Administrator group can log and view counter data only if the tool they use to log and view counter data is started from a Command Prompt window that is opened with Run as administrator.... Users in the Performance Monitoring Users group can view counter data.

Problems with system() calls in Linux

I'm working on a init for an initramfs in C++ for Linux. This script is used to unlock the DM-Crypt w/ LUKS encrypted drive, and set the LVM drives to be available.
Since I don't want to have to reimplement the functionality of cryptsetup and gpg I am using system calls to call the executables. Using a system call to call gpg works fine if I have the system fully brought up already (I already have a bash script based initramfs that works fine in bringing it up, and I use grub to edit the command line to bring it up using the old initramfs). However, in the initramfs it never even acts like it gets called. Even commands like system("echo BLAH"); fail.
So, does anyone have any input?
Edit: So I figured out what was causing my errors. I have no clue as to why it would cause errors, but I found it.
In order to allow hotplugging, I needed to write /sbin/mdev to /proc/sys/kernel/hotplug...however I ended up switching around the parameters (on a function I wrote myself no less) so I was writing /proc/sys/kernel/hotplug to /sbin/mdev.
I have no clue as to why that would cause the problem, however it did.
Amardeep is right, system() on POSIX type systems runs the command through /bin/sh.
I doubt you actually have a legitimate need to invoke these programs you speak of through a Bourne shell. A good reason would be if you needed them to have the default set of environment variables, but since /etc/profile is probably also unavailable so early in the boot process, I don't see how that can be the case here.
Instead, use the standard fork()/exec() pattern:
int system_alternative(const char* pgm, char *const argv[])
{
pid_t pid = fork();
if (pid > 0) {
// We're the parent, so wait for child to finish
int status;
waitpid(pid, &status, 0);
return status;
}
else if (pid == 0) {
// We're the child, so run the specified program. Our exit status will
// be that of the child program unless the execv() syscall fails.
return execv(pgm, argv);
}
else {
// Something horrible happened, like system out of memory
return -1;
}
}
If you need to read stdout from the called process or send data to its stdin, you'll need to do some standard handle redirection via pipe() or dup2() in there.
You can learn all about this sort of thing in any good Unix programming book. I recommend Advanced Programming in the UNIX Environment by W. Richard Stevens. The second edition coauthored by Rago adds material to cover platforms that appeared since Stevens wrote the first edition, like Linux and OS X, but basics like this haven't changed since the original edition.
I believe the system() function executes your command in a shell. Is the shell executable mounted and available that early in your startup process? You might want to look into using fork() and execve().
EDIT: Be sure your cryptography tools are also on a mounted volume.
what do you have in initramfs ? You could do the following :
int main() {
return system("echo hello world");
}
And then strace it in an initscript like this :
strace -o myprog.log myprog
Look at the log once your system is booted

How can my C/C++ application determine if the root user is executing the command?

I am writing an application that requires root user privileges to execute. If executed by a non root user, it exits and terminates with a perror message such as:
pthread_getschedparam: Operation not permitted
I would like to make the application more user friendly. As part of its early initialization I would like it to check if it is being executed by root or not. And if not root, it would present a message indicating that it can only be run by root, and then terminate.
getuid or geteuid would be the obvious choices.
getuid checks the credentials of the actual user.
The added e in geteuid stands for effective. It checks the effective credentials.
Just for example, if you use sudo to run a program as root (superuser), your actual credentials are still your own account, but your effective credentials are those of the root account (or a member of the wheel group, etc.)
For example, consider code like this:
#include <unistd.h>
#include <iostream>
int main() {
auto me = getuid();
auto myprivs = geteuid();
if (me == myprivs)
std::cout << "Running as self\n";
else
std::cout << "Running as somebody else\n";
}
If you run this normally, getuid() and geteuid() will return the same value, so it'll say "running as self". If you do sudo ./a.out instead, getuid() will still return your user ID, but geteuid() will return the credentials for root or wheel, so it'll say "Running as somebody else".
#include <unistd.h> // getuid
#include <stdio.h> // printf
int main()
{
if (getuid()) printf("%s", "You are not root!\n");
else printf("%s", "OK, you are root.\n");
return 0;
}
I would recommend NOT making this change, but instead improving your error message. It's doubtful that your application actually needs to "be root"; instead it needs certain privileges which root has, but which operating systems with fine-grained security controls might be able to grant to the application without giving it full root access. Even if that's not possible now, it may be possible 6 months or 2 years from now, and users are going to be irritated if your program is refusing to run based on backwards assumptions about the permission model rather than just checking that it succeeds in performing the privileged operations it needs to.
What you really want to check for is if you have the right capability set (CAP_SYS_NICE I think is the capability you need) see man pages capabilities (7) and capget (2) this way it won't error out if you have the ability to do what you want, but you aren't root.