Become root after app starts - node.js

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.

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:
Starting as root
Immediately changing the effective user id to a safer user
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.

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.

Related

why does running `which` in a node child process result in different results?

when running the which command in terminal (for example, which yarn), I get a different result from when I'm running a node script (from the same location) which calls execSync('which yarn')
can someone explain why?
tldr;
// in terminal
which yarn
// results in
/Users/xxx/.nvm/versions/node/v17.1.0/bin/yarn
// in node
execSync('which yarn')
// results in
/var/folders/0j/xxx/T/yarn--xxx/yarn
It looks like the Node.js process is running as a different user (not as you), and that user has a different path from your account (or at least, it isn't running any .bashrc or similar specific to your user account that might add to the path). That makes sense given that your result refers to a folder specific to you (/Users/xxx/), but the one from Node.js refers to a central location shared by all users.

What is the difference between `process.env.USER` and `process.env.USERNAME` in Node?

This is the most robust documentation I can find for the process.env property: https://nodejs.org/api/process.html#process_process_env.
It mentions USER, but not USERNAME. On my machine (Windows/Bash), when I print the contents of process.env, I see USERNAME (my windows username) but not USER. Similarly, echo $USERNAME shows my name but echo $USER returns nothing.
What is the difference between USER and USERNAME? Is it an operating system thing? Are they interchangeable?
The documentation about process.env that you linked to shows an example environment; it is not meant to be normative. process.env can be basically anything -- its values generally have OS defaults provided by the shell, but ultimately they are controlled by the user and/or the process that launched your process.
ie, a user could run
$ USER=lies node script.js
...and process.env would not contain the real username.
If you're interested in getting information about the user your process is running as, call os.userInfo(), which is (mostly1) consistent across platforms.
> os.userInfo()
{ uid: -1,
gid: -1,
username: 'josh',
homedir: 'C:\\Users\\josh',
shell: null }
1 - on Windows, uid, gid, and shell are useless, as seen above
os.userInfo() calls uv_os_get_passwd, which returns the actual current effective user, regardless of what's in environment variables.
uv_os_get_passwd Gets a subset of the password file entry for the current effective uid (not the real uid). The populated data includes the username, euid, gid, shell, and home directory. On non-Windows systems, all data comes from getpwuid_r(3). On Windows, uid and gid are set to -1 and have no meaning, and shell is NULL.
process.env is the process's environment variables, which are supplied by the OS to the process.
This object can really contain just about anything, as specified the OS and the process that launches it, but by default Windows stores the username in USERNAME and Unix-like systems (Linux, macOS, etc.) store it in USER.
I was having a similar issue when trying to connect node.js to mysql via dotenv.
None of the many answers in the web did not resolve my issue.
This worked perfectly well, without the .env file, but only with the information required for authentication inserted into the app.js file. I have tried unsuccessfully any of the posted answers, which include (but not only):
changing the information inside the .env file to be with and without ""
changing the name of the .env file
changing the path of the .env file
describing the path to .env file
writing different variations of the dotenv commands inside app.js
At last, I have tried to find if I had installed the dotenv using the npm install dotenv command. Also I have tried to show the version of the dotenv from the console.log(dotenv.MY_ENV_VAR); which again, showed undefined.
The issue was related to the fact, that dotenv confused USER (of the system, again like you I was using Linux) with USERNAME (of the mysql database). Actually USER returns the current system user instead of the mysql database user, which I have set to USERNAME in the .env file for convenience. Now it was able to connect to the database!
To check this, you could use:
console.log(process.env.USER);
and:
console.log(process.env.USERNAME);
1st gives you the system user, whereas the 2nd gives the database user.
Actually, any name for the variable, that holds the username of the mysql database could be used, as far as it does not match the reserved name for the system username in Linux, which is USER.

The linux's permission

Description:
I used root account login in,and create a file (only root can write & read)in other account(if user is test)home directory.issues comming,when i use test account login in ,use 'vim' & 'wq!' command unexpectedly can save success!!,what happen ?why?
It is very difficult to understand your post. I'm really trying to, but I might interpret it wrongly:
You log in as root and create a file in user test's home directory?
Then, you log out from root and log in as test?
Then, as user test, you launch Vim and issue command "force write & quit?
You are perplexed as to why you are allowed to create a file as user test, inside a directory owned by user test?

How to create linux terminal like tutorialspoint?

TutorialsPoint Java Compiler
In tutorialspoint, they have created linux terminal using term.js.
I have integrated same github library in my project, it is working fine but I am trying to understand the flow of tutorialspoint.
My assumption:
In tutroialspoint each time they are creating new user_id under root user(cg) and running terminal(nodejs server) using that user_id so every time when you reload page there will be a different user_id (run whoami in terminal), so another user can't operate other users files.
I am running nodejs server using forever.js under root user, I want to implement same type of functionality. What is correct way to do this? and if there is another way please elaborate.
I think they are creating a new user each time you visit the page and providing you a subshell of that user. It can be easily achieve by using Shell Programming techniques. Creating a new user each time thing is probably nothing more than a security measure.
So I will briefly explain the concept in 5 steps:
1 - Create a new user:
shell_exec('useradd --expiredate 2016-09-10 [username]');
http://www.computerhope.com/unix/useradd.htm
2 - Login to this newly created user account:
shell_exec('su [username]');
3 - Get user input to the PHP script using AJAX(dynamically).
4 - Execute user's command and send the output to user:
<?php
$output = shell_exec("[user's command]");
echo "<pre>$output</pre>";
?>
5 - Repeat from 3.

fabric -- cant run commands after user is switched

I have been recently introduced to fabric and trying to approach the following:
access remote host
su root
perform a command, for example change password for multiple users
done!
Please note that I cant use sudo, nor connect directly to the remote host using root. The commands I need to perform can only be performed if I explicitly change user to root.
I was able to approach the main concept of getting to the remote host and play with some commands, using fabric, but the problem im having is that once I switch to root "su root" I cant perform the rest of the commands unless I exit.
example of what im trying to approach:
def mytask():
with settings(user="root"):
run('whoami')
run('echo "TEST using root user"')
run('echo "ITS WORKING!!!"')
or something like this
def mytask():
run ('su root')
run ('passwd testUser')
In both cases once I enter the root password nothing would get executed, I would get the remote command line back, unless I exit back to the original user. I have seen few suggestions about using "fexpect" for prompts but not sure if that would make a difference.
I'm developing on a Linux environment.
You have to use fexpect and fexpect run command
from ilogue import fexpect
prompt = ['Password', 'mypassword'] # ('prompt', 'answer') Case sensitive
def test():
with fexpect.expecting(prompt):
fexpect.local("su -")

Resources