dotbot icon indicating copy to clipboard operation
dotbot copied to clipboard

Add "sudo" option to `link` plugin

Open nagromc opened this issue 7 years ago • 32 comments

Dotbot is used by multiple usersincluding me — to symlink files in folders that need root privileges.

It would be nice to add an option (just like path or create) to the link plugin to describe if the target needs to be symlinked with root privileges. We could name this option sudo or root.

For example:

- link:
    /etc/some/restricted/path/whatever.conf: whatever.conf
        create: true
        sudo: true
    ~/.vimrc: vimrc
        sudo: false

Running ./install would create two symlinks:

  • /etc/some/restricted/path/whatever.conf created as root
  • ~/.vimrc created as regular current user

If you prefer to keep Dotbot simple, we could create a plugin that extends the link plugin.

nagromc avatar May 31 '17 12:05 nagromc

The idea sounds good! Having a sudo option on link seems useful. A couple questions:

  1. When would the user enter the password?
  2. Would you be interested in implementing this?

anishathalye avatar May 31 '17 13:05 anishathalye

Great!

  1. When would the user enter the password?

According to the man pages, sudo seems to cache the password for 15 minutes by default (at least on the latest Ubuntu LTS):

Security policies may support credential caching to allow the user to run sudo again for a period of time without requiring authentication. The sudoers policy caches credentials for 15 minutes, unless overridden in sudoers(5).

So I think the password should be asked by sudo itself to let it cache the credentials. So when the user runs ./install, as soon as Dotbot process a link with sudo option enabled, the password prompt appears. Would it be a good UX?

  1. Would you be interested in implementing this?

Yeah sure. Just to let you know I'm not used to code in Python, but I'm rigorous in my work and I love to learn. I will try my best and will submit a PR.

nagromc avatar May 31 '17 14:05 nagromc

  1. Well, we use Python's os.symlink() function to create symlinks. I don't think we want to switch to shelling out to sudo ln -s .... I'm not sure what's the recommended way of doing this with Python.

  2. Ok, sounds great! I can give you feedback on the code 😄 And feel free to ask if you have any questions.

anishathalye avatar May 31 '17 14:05 anishathalye

I personally think that shelling out is not a good practice. Likewise running dotbot as a super user or making system config's symbolic links somewhere in the a user's home directory is a terrible idea.

In issue #128 I suggest to mimic the options for the install(1) command trough copy:, which sets the file's attributes (access controls). Surely it would be no problem to run an idempotent installer (but you'll have to remember) after editing files yet-to-be copied. The install command also allows for a simple in-place backup to be made (maybe also to clean old backups).

I'll reflect upon this subject, and I'll look around to find out how to achieve this with syscalls and subprocess privileges. (However, I'm not a programmer ...) Please let me hear your thoughts.

edit: privilege dropping script

sharethewisdom avatar Jun 25 '17 12:06 sharethewisdom

+1

ShikherVerma avatar Aug 03 '17 02:08 ShikherVerma

I encourage users to manage /etc with etckeeper, which uses git. It has hooks for common package managers. Make sure to take a look at Automatic push to remote repo on the page I linked. A remote repo could obviously be a thumb drive, a repo on a computer in your LAN or a private repo on the public internet.

Still it would be cool indeed if Dotbot could drop privileges and change file attributes without shelling out.

sharethewisdom avatar Aug 03 '17 08:08 sharethewisdom

Using this ugly line now :sob: wish dotbot had sudo support for link.

ShikherVerma avatar Aug 03 '17 08:08 ShikherVerma

@ShikherVerma i'd use [ -e /etc/fonts/local.conf ] || sudo ln fontconfig /etc/fonts/local.conf to make it slightly prettier

ashkitten avatar Aug 03 '17 12:08 ashkitten

I have nothing against adding some kind of sudo functionality to link, as long as it's implemented in some reasonable way. Does anyone have good ideas for how to do this?

anishathalye avatar Aug 03 '17 20:08 anishathalye

@anishathalye you are welcome to take inspiration from my dotbot-yum plugin where I implemented a "sudo: true" param - https://gitlab.com/flyingchipmunk/dotbot-yum

edit: ah scratch that just went and looked at link.py, it's using os.symlink(...), not easy to shoehorn sudo in there. Maybe an option for folks is to have a different install_links.conf.yaml with only the link directives and sudo dotbot -c install_links.conf.yaml

That way the security is handled by the os layer instead of managing it in link.py

flyingchipmunk avatar Sep 28 '17 04:09 flyingchipmunk

Ok, does somebody want a separate plugin that will do link with sudo rights? It would add a keyword, say, linksu and all /etc/ stuff etc should be linked via this plugin.

Most probably there will be a need to shell out though if the password is prompted on Python side and passed via STDIN the whole thing should be more or less secure.

ddnomad avatar Feb 03 '18 10:02 ddnomad

We can even include such functionality in Dotbot core, as long as we have some reasonable way to do it.

I don't think there's too much to worry about security: everything in this scenario is trusted (Dotbot + everything else in your dotfiles).

Also, it's fine to have it start out as a plugin, and if there's interest, we can merge it into core at some point.

anishathalye avatar Feb 03 '18 14:02 anishathalye

Good point! I'll do my best to squeeze out some time to make a pilot version of a plugin. I'll let you know when there will be something.

ddnomad avatar Feb 03 '18 15:02 ddnomad

@anishathalye Can you clarify what the major hurdle is for implementing this functionality into core?

You mention implementing it in a "reasonable" way a couple of times. Can you clarify what that means?

To answer the questions you asked...

1. When would the user enter the password?

Without too much thought here, I would imagine this would happen when the code first encounters a link target that requires elevated privileges, no?

In 99% of the cases, the user would just have to enter the password one time because, according to the sudo man page...

"[...] the default password prompt timeout for the sudoers security policy is 5 minutes."

which is well beyond the time it would take to execute the entire program (and, if not, the user will just have to enter it a second time if sudo is needed again).

Is there something that I'm missing here that makes this more complicated?

2. Would you be interested in implementing this?

Yep, very much so. Only interested if this goes directly into core though. Not a plugin.

dsifford avatar Feb 16 '18 01:02 dsifford

I don't really have a set of rules that I can write down to explain what I mean by "reasonable" implementation. One example of something that I think won't be good enough is shelling out to sudo ln -s. At the very least, the solution should be robust (no worse error handling than the current version) and cross-platform.

anishathalye avatar Feb 16 '18 02:02 anishathalye

Fair enough. Thanks for chiming back.

Might take a stab at this either this weekend or next if time allows. (unless @ddnomad has already got something together that satisfies those provisions).

dsifford avatar Feb 16 '18 02:02 dsifford

@dsifford mine version is just a sketch right now and I do shell out. Thus you definitely can take a stab yourself.

ddnomad avatar Feb 16 '18 06:02 ddnomad

@ddnomad @anishathalye Gonna unfortunately tap out of this one.

Ergonomics are too weird to contribute. I really don't want to install vagrant just to run tests (though, I do appreciate the reason it's being used -- encapsulation).

I still think that simply adding a "sudo" field that accepts a boolean that, when true, runs sudo -u "$USER" ln -s [...] is totally an acceptable and easy to implement solution.

dsifford avatar Feb 23 '18 22:02 dsifford

@dsifford That would need special configuration for windows users though as people might use dotbot for non-unix/linux OS'.

mainrs avatar Apr 04 '18 16:04 mainrs

@SirWindfield Why would windows users even use the sudo option?

dsifford avatar Apr 04 '18 16:04 dsifford

No idea, aren't there protected directories too? o.O

Anyway, I just had a small idea. Maybe link each normal file first and after that, re-run the script (automatically) passing it a flag like sudo=true. Dotbot would then only link all files that are declared as sudo. Youd could even change the owner of the files to the sudo caller by using SUDO_UID and SUDO_GID environment variables and calling os.chown. It would basically be a two step process.

mainrs avatar Apr 04 '18 16:04 mainrs

Just came across this issue, this is something I've been looking for ever since I've started using dotbot back in 2015!

Definitely keeping an eye on this one!

FatBoyXPC avatar Sep 27 '19 05:09 FatBoyXPC

Isn't this a security issue? Linking a system file to a user-writable target would let any process running as that user change the file, which kind of defeats the purpose of having system files in the first place. For some files (e.g. systemd unit overrides) this would effectively allow the user to run arbitrary processes at root, without even noticing.

Personally I use shell to install system files, e.g.

- shell:
 - command: sudo -n install -D -m644 systemd/timesyncd.conf /etc/systemd/timesyncd.conf
    stderr: true

sudo -n makes sudo fail if it would have to prompt for password, so that ./install runs without stopping at any prompts even if I have no active sudo ticket. To install system files I use sudo -v && ./install which acquires a sudo ticket before installing my dotfiles.

swsnr avatar Nov 08 '19 13:11 swsnr

I actually want those systemd overrides. In this case, one would also need to ProtectHome=no - so at least you know you're doing something that comes with some risk.

Using shell works, but then you kind of lose the niceness of the yaml config. I found custom install scripts on the wiki and I've created install.sudo.conf.yaml and an install-sudo script. I think this is a good compromise.

I used to ./install and immediately follow it with sudo ./install - but that would put a bunch of symlinks in root's directory, which was obviously not preferable. Now I have shell with sudo ./install-sudo in it, so ./install can take care of all of it, with nothing irrelevant going to root's directory.

FatBoyXPC avatar Nov 08 '19 15:11 FatBoyXPC

any news on this?

dagadbm avatar Jul 15 '20 17:07 dagadbm

I think the install-sudo script is an alright enough way to go. That allows things to stay separate if need be.

See these files: install-sudo, install.sudo.conf.yaml, and install.conf.yaml

FatBoyXPC avatar Jul 15 '20 18:07 FatBoyXPC

Yeah, I think that's the recommended approach, at a high level. Have two separate .conf.yaml files, and call Dotbot on each, once without sudo, and the other time with sudo.

You could use variations of that, e.g. having an install.conf.yaml and a sudo.conf.yaml, and then having your ./install script itself be modified to call Dotbot on each of those (I think I would do that rather than putting a shell: line in the install.conf.yaml).

anishathalye avatar Jul 15 '20 19:07 anishathalye

I honestly didn't even thinking about having the install script call sudo.conf.yaml!

FatBoyXPC avatar Jul 15 '20 19:07 FatBoyXPC

Hi, I also had the problem, that i needed to execute parts of my install.con.yaml as root. So I write a plugin for this purpose. Maybe this could help you too: dotbot-sudo Please let me know what you think :)

DrDynamic avatar Nov 16 '20 11:11 DrDynamic

You could add it to the plugins list for extra visibility.

anishathalye avatar Nov 17 '20 11:11 anishathalye

Added some plugins to the plugin list :)

DrDynamic avatar Nov 18 '20 06:11 DrDynamic

I know this is really outdated, but the new install scripts solve this problem by allowing you to add -sudo to the end of any configuration. i.e. ./install-standalone some-config other-config-sudo. Only downside is that it requires you to have implemented the more advanced setup from the Tips and Tricks section of the wiki.

ecarlson94 avatar Apr 19 '21 17:04 ecarlson94