Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run commands as a different user (sudo -i) #122

Open
bitc opened this issue May 23, 2016 · 9 comments
Open

Run commands as a different user (sudo -i) #122

bitc opened this issue May 23, 2016 · 9 comments

Comments

@bitc
Copy link

bitc commented May 23, 2016

A nice feature to have would be the ability to run a command as a different unix user (sudo -i).

Haskell's process package supports this with the child_group and child_user fields of CreateProcess [1]

I can think of two ways for Shelly to support this:

  1. Add variants of the run and run_ functions that take an extra UserId argument
  2. Add a function withUser :: UserId -> Sh a -> Sh a that starts a sub-Sh in which all commands will be run as the requested UserId. This requires adding field(s) to Shelly.State

Either way, this functionality would probably belong in the Shelly.Unix module.

I would appreciate feedback on this idea, and I can work on a pull request.

[1] https://hackage.haskell.org/package/process-1.4.2.0/docs/System-Process.html#t:CreateProcess

@gregwebs
Copy link
Owner

Sounds like a good idea, and also one that should be easy to add. The only hard part would be in surfacing good error messages and creating automated testing.

I don't think think this is Unix specific. The second approach should work. shellyProcess can then pull the user out of the state.

@bitc
Copy link
Author

bitc commented May 23, 2016

Cool! Question:

In addition to setting child_user, should we also support setting the child_group (sudo -g option)? I myself am not too sure what use cases this is for...

@gregwebs
Copy link
Owner

Up to you. I usually add things when I need them

@bitc
Copy link
Author

bitc commented May 23, 2016

I started to implement this, but I realized that there is a problem.

All of shelly's builtin commands, such as cp and writefile will not behave as expected (they won't run as the correct user id). It might be possible to modify them to work properly by using setUserID, but in order for that to work well with any other threads we would need to also first forkProcess, which is documented to have problems when used with threads (and is not portable)...

I'm thinking it might be cleaner/better to go with option (1) that I proposed above. Anyway, I will think about this for a bit before proceeding and of course would be interested in hearing other thoughts.

btw, I noticed that there is a commented out run_sudo function. Is there a story behind this?

@gregwebs
Copy link
Owner

You are right, that is problematic. I don't think forkProcess would be a problem for us though because we are controlling that it is just forking to run a command, so there is no way to reference a resource on another thread. But the fact that it doesn't work on Windows is certainly an issue.

If the only use case is to run as sudo, a run_sudo command makes sense, but then when you need to copy you need to make sure to run_sudo cp rather than cp. Maybe this is something where the Sudo newtype could help out with because only run_sudo makes the newtype.

@bitc
Copy link
Author

bitc commented May 24, 2016

Regarding forkProcess

From the docs:

GHC note: forkProcess is not currently supported when using multiple processors (+RTS -N), although it is supported with -threaded as long as only one processor is being used.

Are shelly programs commonly run with +RTS -N?

More discussion

My intended use case is actually to run some commands as a non-admin user, from a shelly script that starts running as root.

I imagine that the use case of running commands as root would be more common (sudo apt-get install ...). In fact, for this case, I believe that the only way for this to work is to go through the "/usr/bin/sudo" program. Trying to set child_user as root will fail immediately (without prompting for a password). And I don't think that there is any other syscall that can accomplish this [1].

So adding sudo-like functionality to shelly, so that cp and writefile can run as root, seems impossible (without crazy hacks).

This makes me lean even more towards option (1)...

[1] http://stackoverflow.com/questions/1970329/how-do-i-sudo-the-current-process

@gregwebs
Copy link
Owner

hmm. If I have sudo in a bash script it will prompt me to elevate privileges. Maybe this is a weakness to not using bash.

When starting the script as root, there isn't a clear way to copy a file as non-root. So run_as_user makes sense. It still seems more ideal to have a asUser function to change the user for most of the script, but it would actually need to set the user of the entire program. It could be called unsafe_asUser and document that it should never be used in a threaded/concurrent program. So this is dangerous, but would also allow for copying a file, etc.

@bitc
Copy link
Author

bitc commented May 24, 2016

I'm not sure if I understand what you meant, but if you have a bash script that does:

#!/bin/bash

# /etc/shadow is only readable by root
sudo cat /etc/shadow

Then it will run the "/usr/bin/sudo" command, which will prompt for a password, and then it is the sudo program itself that will run cat /etc/shadow with elevated privileges. But the running bash process itself never gets these elevated privileges.

In the case of shelly, it is possible to do something similar: run "/usr/bin/sudo" with the proper arguments, in order to run the command cat /etc/shadow. But it is impossible in shelly to use sudo (or any other technique) in order to be able to run the haskell code readFile "/etc/shadow" with elevated privileges.

@gregwebs
Copy link
Owner

ahh, ok. Does it make sense to have an unsafe_withUser function that changes the user of the process with setUserId ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants