Equivalent to setuid for non-root users

Does Linux have some C-interface, similar to setuid , which allows the program to switch to another user using, for example, username / password? The problem with setuid is that it can only be used by superusers.

I am running a simple web service that requires you to complete tasks as a registered user. Thus, the main process runs as root, and after the user enters the forks into it and calls setuid to switch to the corresponding uid. However, I'm not quite sure that the main proc is running as root. I would prefer it to work as another user and have some mechanism to switch to another user like su (but without starting a new process).

+4
source share
2 answers

No, there is no way to change the UID using only the username and password. (The concept of โ€œpasswordโ€ is not recognized by the kernel in any way - it exists only in user space.) To switch from one non-root UID to another, you must become root as an intermediate step, usually exec() releasing the setuid binary.

Another option in your situation may be to start the main server as an unprivileged user and to associate it with an internal process running as root.

+4
source

First, setuid() can definitely be used by non-superusers. Technically, all you need on Linux is the CAP_SETUID (and / or CAP_SETGID ) ability to switch to any user. Secondly, setuid() and setgid() can change the process identifier between the real (the user who executed the process), effective (owner of the setuid / setgid binary) and stored identifiers.

However, none of this is relevant to your situation.

There is a relatively simple but extremely reliable solution: to have a helper setuid helper forked and executed by your service daemon before it creates any threads, and use a pair of Unix domain sockets for communication between the helper and the service, a service that passes as its credentials , as well as channel endpoint file descriptors for the helper when binary user files are executed. The assistant will check everything at a safe level, and if everything is in order, it will wag and execute the desired user assistant, and the indicated connection endpoints are connected to standard inputs, standard outputs and standard error.

The procedure for starting the Assistant service is as follows:

  • Create a pair of Unix sockets used for privileged messages between the service and the helper.

  • Fork.

  • In the child, close all the extra file descriptors, saving only one end of the socket pair. Remap standard input, output, and error to /dev/null .

  • In the parent element, close the child end of the socket pair.

  • In the child case, execute the privileged auxiliary binary.

  • The parent sends a simple message, possibly without any data, but with the auxiliary message / dev / random, but remember that this is a limited resource (it can be blocked if there is not enough randomness for the kernel). I would just read, say 1024 bits (128 bytes) from /dev/urandom , and use this.

    At this point, the helper determined that the other end of the pair of sockets is your service daemon, and the assistant can trust control messages as much as the service daemon trusts. (I assume that this is the only mechanism on which the service daemon will spawn user processes, otherwise you will need to re-pass the credentials in each subsequent message and re-check them every time in the assistant.)

    Whenever a service daemon wishes to execute custom binary code, it

    • Creates the necessary channels (one to supply standard input to the user's binary file, one to return standard output from the user's binary file)

    • Sends a message to an assistant containing

      • Identity to run the binary as; user names (and groups), or UID and GID (s)
      • Path to binary
      • Binary command line options
      • Auxiliary message containing file descriptors for user binary data endpoints.

    Whenever a helper receives such a message, he forks. In the child element, it replaces standard input and output with file descriptors in the auxiliary message, changes the identifier with setresgid() and setresuid() and / or initgroups() , changes the working directory to the desired location, and executes the user binary. The parent helper process closes the file descriptors in the helper message and waits for the next message.

    If the assistant shuts down when there is no more input from the socket, it will automatically exit when the service exits.

    I could provide sample code if there is enough interest. There are many details to get it right, so the code is a little tedious to write. However, correctly spelled, it is safer than, for example, Apache SuEXEC.

+9
source

Source: https://habr.com/ru/post/1441681/


All Articles