c++clinuxauthenticationpam

How to run a command as root with C or C++ with no pam in linux with password authentication


TL;DR How does for example su or sudo work with no PAM?

Hello,

I want to play around with suid and stuff, I already got the SUID part and the SUID bit and stuff, but the problem is that it's not asking me for a password and as I want it to ask a password and find su and sudo quite mangled in source I am very confused.

I looked into setsuid() and getuid() documentation and it doesn't seem like there is anything about password authentication.

How would one achieve password authentication with no PAM, I use sudo with no pam and it works fine, su with pam, both work fine, I am confused how I'd make it work

This C++ code is what I have right now:

// a.cc //

#include <iostream>
#include <unistd.h>
#include <cerrno>
#include <cstring>

int main(int argc, char *argv[]) {
    uid_t user = getuid();
    if (setuid(0) == -1) {
        std::cerr << strerror(errno) << '\n';
        return 1;
    }

    system(argv[1]);

    if (setuid(user) == -1) {
        std::cerr << errno << '\n';
        return 1;
    }
    return 0;
}

and after compiling it with for example GCC and the file being named a.cc:

$ g++ a.cc -o a

and giving it execute and SUID permissions and giving the ownership to root

$ sudo chown root:root ./a
$ sudo chmod 4555 ./a

it just works, but without password authentication

$ ./a id

uid=0(root) gid=1000(ari) groups=1000(ari),5(tty),10(wheel),27(video),78(kvm),250(portage)

(ari is my user)

Even after logging out or running sudo -k to end sudo timeout it still works with no password authentication.

Thanks for answers in advance


Solution

  • First, the basics: each process has a userid and a groupid (I am going to ignore supplemental attributes like additional groupids).

    Userid 0 is root. That's it, end of story.

    When you have a process whose userid is 0, it's a root process. End of story.

    How a process acquires its userid 0 is immaterial. If a process's userid is 0, it is a root process, and that's it.

    When you go through the motions of setting up a setuid process, that setuid(0)s itself, you're done. You're a root process. That's it. There's nothing more to say about it.

    setsuid() and getuid() documentation and it doesn't seem like there is anything about password authentication.

    Correct. All they do is adjust/update the userid. That's it. There's nothing more to it.

    The su and sudo processes do the following:

    1. They are setuid executables.
    $ ls -al /bin/su /bin/sudo
    -rwsr-xr-x. 1 root root  57504 Aug 17 04:59 /bin/su
    ---s--x--x. 1 root root 185440 Aug  7 13:17 /bin/sudo
    

    Does this look familiar to you? Your hand-made setuid program's permissions looks identical to this, doesn't it?

    1. But before they go any further, they demand that you provide an acceptable password (or meet some other criteria, in some form or fashion, it is immaterial what the exact details of acceptable authentication criteria is, a password in su's case, or an acceptable match in sudo's configuration). If you don't they terminate with no further action taking place.

    All the password validation logic, involving PAM or some other authentication framework, is implemented by the su and sudo processes themselves. Unless you provide acceptable authentication credentials (whatever it means for su or sudo) they terminate with no further action taking place. A successful authentication results in a shell, or an executed command, but that's for the very simple, elementary reason that the su and sudo programs themselves used setuid (the permission bit and the system call) to acquire root privileges, as the first order of business.