Removing root privileges

I have a daemon that runs as root (so it can communicate with low ports). After initialization, I would really like it to reset root privileges for security reasons.

Can someone point me to a known correct piece of code in C that will do this?

I read the manual pages, I looked at various implementations of this in different applications, and they are all different, and some of them are really complex. This is security related code, and I really don't want to invent the same mistakes as other people. What I'm looking for is best practice, a well-known good portable library function that I can use, knowing that everything will be correct. Is there such a thing?

For reference: I start with root; I need to change to work under a different uid and gid; I have to configure additional groups correctly; After that, I do not need to change root privileges.

+44
c unix root
Jul 28 2018-10-21T00:
source share
3 answers

You are looking for this article:

POS36-C. Follow the correct recall procedure, giving up privileges

Not sure how best to post some information without duplicating the contents of this page ...

+11
Mar 18 '15 at 10:05
source share

To refuse all privileges (user and group), you need to drop the group in front of the user. Given that userid and groupid contain the identifiers of the user and group to which you want to go, and assuming that the effective identifiers are also root, this is achieved by calling setuid () and setgid () :

 if (getuid() == 0) { /* process is running as root, drop privileges */ if (setgid(groupid) != 0) fatal("setgid: Unable to drop group privileges: %s", strerror(errno)); if (setuid(userid) != 0) fatal("setuid: Unable to drop user privileges: %S", strerror(errno)); } 

If you are paranoid, you can try to regain your root privileges, which should fail. If this does not work, you will get help:

  if (setuid(0) != -1) fatal("ERROR: Managed to regain root privileges?"); 

In addition, if you are still paranoid, you can seteuid () and setegid () , but this is not necessary, since setuid () and setgid () have already set all identifiers if the process belongs to root.

The list of additional groups is a problem because there is no POSIX function for setting additional groups (there are getgroups () , but no group groups ()). There is a BSD and Linux extension setgroups () that you can use, this is for you.

You must also chdir("/") or any other directory so that the process does not remain in the root directory.

Since your question is about Unix in general, this is a very general approach. Please note: on Linux, this is no longer the preferred approach. In current versions of Linux, you must set the CAP_NET_BIND_SERVICE feature in the executable file and run it as a regular user. No root access needed.

+42
Jul 28 2018-10-21T00:
source share

Here is what I could do best:

 #define _GNU_SOURCE // for secure_getenv() int drop_root_privileges(void) { // returns 0 on success and -1 on failure gid_t gid; uid_t uid; // no need to "drop" the privileges that you don't have in the first place! if (getuid() != 0) { return 0; } // when your program is invoked with sudo, getuid() will return 0 and you // won't be able to drop your privileges if ((uid = getuid()) == 0) { const char *sudo_uid = secure_getenv("SUDO_UID"); if (sudo_uid == NULL) { printf("environment variable `SUDO_UID` not found\n"); return -1; } errno = 0; uid = (uid_t) strtoll(sudo_uid, NULL, 10); if (errno != 0) { perror("under-/over-flow in converting `SUDO_UID` to integer"); return -1; } } // again, in case your program is invoked using sudo if ((gid = getgid()) == 0) { const char *sudo_gid = secure_getenv("SUDO_GID"); if (sudo_gid == NULL) { printf("environment variable `SUDO_GID` not found\n"); return -1; } errno = 0; gid = (gid_t) strtoll(sudo_gid, NULL, 10); if (errno != 0) { perror("under-/over-flow in converting `SUDO_GID` to integer"); return -1; } } if (setgid(gid) != 0) { perror("setgid"); return -1; } if (setuid(uid) != 0) { perror("setgid"); return -1; } // change your directory to somewhere else, just in case if you are in a // root-owned one (eg /root) if (chdir("/") != 0) { perror("chdir"); return -1; } // check if we successfully dropped the root privileges if (setuid(0) == 0 || seteuid(0) == 0) { printf("could not drop root privileges!\n"); return -1; } return 0; } 
+1
Jun 20 '17 at 16:30
source share



All Articles