3

On occasion, the user initiates an action in my Node app that requires escalated administrator or root privileges. Rather than ask users to run the app with sudo, I would like to prompt the user for their password and escalate the privileges of the already-running Node process.

I am not interested in my app executing a child process with sudo (as is already possible with sudo-prompt). I want the node process itself to gain root privileges after having been started by a non-root user without sudo.

One example of an app that displays behavior exhibiting the problem:

var process = require('process');
var http = require('http');
var server = http.createServer(...);
// Several steps here that are unsafe to run as root
promptUserForAdminPassword();
server.listen(80); // Fails, needs to be root

I would like to write the function promptUserForAdminPassword(), which would prompt the user for their password, escalating the privileges of Node so it can run server.listen(80) with root privileges, but run everything prior with user privileges.

Cory Klein
  • 51,188
  • 43
  • 183
  • 243
  • 1
    This is actually a reply to your comment on Gabriel's answer, but I thought it belonged better up here. What we do best here is to understand the overall problem and suggest solutions and we often find solutions that are way better than anything the OP has thought of or asked about. You are asking ONLY for one specific solution that nobody seems to have an answer for and you have not described your actual, overall problem scope so we can't offer other solutions. You've handicapped the community here and made it so we probably can't help if your specific ask does not exist. – jfriend00 Jul 13 '17 at 23:43
  • Also, what platform are you running on. Privilege stuff is often different on WIndows vs. *nix. – jfriend00 Jul 13 '17 at 23:44
  • @jfriend00 I disagree. Stack Overflow does not work best for overall solution suggestions, as evidenced by the existence of the Too Broad close reason and it's accompanying description. I'd be happy to discuss further in chat about what makes a good question on SO. – Cory Klein Jul 14 '17 at 01:31
  • By the way - a lack of answer to this question is a sort of answer in itself, and that information is useful. A definitive answer, "What you are asking is impossible because of XYZ," would be even better, because then others who are trying to implement something similar can short circuit their research and change their design. – Cory Klein Jul 14 '17 at 01:44
  • Too Broad is when someone asks an overly broad question that is not specific at all. It never applies when some describes the overall problem they are facing and then shows what solutions they tried and where they got stuck. That perfectly defines the specific problem they are trying to solve (at a high enough level to include the overall context), shows what they tried and where they got stuck and that then allows others to offer them solutions they've never even known of. Good luck with your question I will be moving on now as there doesn't appear to be anything to do here. – jfriend00 Jul 14 '17 at 01:45
  • FYI, it's pretty simple to offer an answer - here's how you could solve your problem. It's pretty hard to confidently know there is no possible solution, thus you rarely get an answer like that and you rarely see useful questions like that here. There are lots of questions here that don't get answers. That, by itself, does not usually answer those questions. It usually just means they couldn't attract anyone (or the right people) to work on their question was too flawed to attract an answer. – jfriend00 Jul 14 '17 at 01:47
  • Indeed. And if I were to describe the general problem I'm trying to solve, it would be Too Broad under the exact definition you describe. What I'm trying to find out here is whether this specific approach is a possibility to pursue. I agree that the silence is a good indication that a solution may not exist. But I'm not going to change my question to provide an easier opportunity for others to gain SO rep. – Cory Klein Jul 14 '17 at 01:49
  • It's not about gaining rep. It's about solving a problem and then leaving a useful reference that can be referred to later (at a high level, those are the two main things stackoverflow is about). You are apparently accusing me of something that isn't happening here. You have a problem. You've not given us enough information for us to offer a solution. I was asking for more information so we might have a chance of offering a different type of solution. You have refused. Bye. – jfriend00 Jul 14 '17 at 01:52
  • @jfriend00 My comment about SO rep was rude and unwarranted, and I apologize. I was frustrated because I felt you were attacking what I believe is a legitimate question. It has not been asked as far as I could find, and I've spent a lot of time researching the answer. The community doesn't have an answer for this question, but that does not make the question a bad or illegitimate one. Until I asked the question, I couldn't know if somebody had an answer. I won't change it now to get an answer to a question I'm not asking. – Cory Klein Jul 14 '17 at 02:02

2 Answers2

4

You are essentially wanting to change the uid of the node process to 0, the id for root. This is done using Node's process.setuid(0), but only root or processes run with sudo will be successful with that call, so this is not possible.

It is not possible for a process with a uid of a non-privileged user to change its uid to 0.

Alternatives

Start Another Process

// Prompts user for password in terminal running Node process
child_process.spawn('sudo', ['node', 'serverlistener.js']);

// Prompts user for password using UI element
child_process.spawn('gksudo', ['node', 'serverlistener.js']);

This question has some options for the missing gksudo on macOS.

Effective User ID

If starting the app with sudo is a possibility, you can reduce the exposure of root by:

  1. Starting as root
  2. Immediately changing the effective user id to a safer user
  3. Later change the effective user back to root as needed

Example:

var userid = require('userid');
var sudoUserId = userid.uid(process.env.SUDO_USER);
process.seteuid(sudoUserId);
// Do things
process.seteuid(0);
server.listen(80);

Uses userid module.

Cory Klein
  • 51,188
  • 43
  • 183
  • 243
1

Usually what you want to do is launch your server as root and then drop permissions, not the the other way around.

https://thomashunter.name/blog/drop-root-privileges-in-node-js/

If all you want to do is run on port 80 then that's what I recommend.

If you need permissions for other things you should probably have the user your server is running as have permission for those things. (write access to directories etc) Running as root is generally bad.

Gabriel Littman
  • 552
  • 3
  • 13
  • Thing is 99% of the time the app is run this privileged feature is not utilized. Starting the app as root is not an option in this case, which is why I worded the question as I did. I need to switch users to root *after* the non-root user has started the app. – Cory Klein Jul 13 '17 at 22:36
  • @CoryKlein - Why is running the app as root not an option. I agree with Gabriel that the common sense way this is done is for the user starting the server to acquire the proper privileges before running the server. If you want your server to tell them what privileges are required if they start it up with insufficient privileges, you could add that help for the user. – jfriend00 Jul 13 '17 at 22:40
  • FYI, there are a number of ways to run on port 80 without running as root. I have a node server running on 8080 and port 80 has been port forwarded to 8080 in an OS config file so the outside world connects to port 80, the OS port forwards that to my server on 8080 and I don't have to run my server with elevated privileges while it appears to be serving port 80. – jfriend00 Jul 13 '17 at 22:41
  • 2
    @jfriend00 It's not an option because there are 100 different necessary code paths encountered *before* the `sudo` privilege is used. These include creating files in various places on the file system. Running the app with `sudo` introduces risk in all those previous steps. Besides, this question is not about "how to solve Cory Klein's" root problem, it is "how to escalate privilege after node starts". If the answer is, "Sorry, you can't", then *that* is the answer. Answers in the form of "You could solve your problem in a different way" are not what I'm looking for. – Cory Klein Jul 13 '17 at 23:00