dirs-rs icon indicating copy to clipboard operation
dirs-rs copied to clipboard

sudo and $HOME

Open zertosh opened this issue 4 years ago • 19 comments

When running with sudo, dirs-rs returns directories for the user calling sudo and not the user that's running under sudo.

On the surface this can seem like expected behavior but it becomes a real problem when a tool is run with sudo, uses dirs::cache_dir, and ends up creating that directory when it doesn't exist.

Unsetting $HOME before using dirs-rs causes dirs-sys-rs's home_dir to use getpwuid_r in the "fallback" logic. This ends up returning the home dir for the user running under sudo. But it's a really ugly workaround. Although sudo has an -H flag to replace $HOME, you don't tend to expect a tool to end up creating a ~/.cache owned by say root when you don't use -H.

I'm not sure if it's a good idea to never trust $HOME, but would it be possible to offer another set of methods that use the "real home dir"?

zertosh avatar Jan 10 '20 02:01 zertosh

A very good observation, thanks @zertosh! I'm trying to think of a solution that "just works" but haven't found anything yet ...

soc avatar Sep 12 '21 17:09 soc

There isn't an universal solution, but you can take a look at the SUDO_USER variable. It is defined by default when running sudo and contains the user that called sudo itself. AFAIK it is either defined with the correct user name, or not defined at all, it should never contain root unless the calling user was root itself.

ClementNerma avatar May 20 '22 13:05 ClementNerma

Hey, Was this issue solved or not yet? I have the same problem, So, Is there any solution?

Hulxv avatar Jul 05 '22 03:07 Hulxv

I was looking at solving this, but the sudo manual describes SUDO_USER as "Set to the login name of the user who invoked sudo," although for me it remains unset. That seems like the bad behavior we're trying to avoid.

Would simply using the fallback function be an acceptable solution?

Kyllingene avatar Oct 03 '23 17:10 Kyllingene

I was looking at solving this, but the sudo manual describes SUDO_USER as "Set to the login name of the user who invoked sudo," although for me it remains unset. That seems like the bad behavior we're trying to avoid.

Would simply using the fallback function be an acceptable solution?

Can I ask which OS you were running with this behaviour?

I have just run into this sudo issue with an application I am working on, and on all the systems I've tested on (albeit on a couple of Ubuntu systems, and a couple or raspberry pi's running PiOs), the SUDO_USER is set, and could help solve this issue.

mrjackwills avatar Jan 21 '24 21:01 mrjackwills

Can I ask which OS you were running with this behaviour?

I was testing using Fish and Arch Linux. I can test again later using bash, perhaps?

Kyllingene avatar Jan 21 '24 21:01 Kyllingene

Ah ok, I'm only using bash.

Could a potential fix for this first check for SUDO_USER, and then fall back to USER? That's basically what I've implemented for my application, using the std::env::var("SUDO_USER") method, to return an Option<String>

mrjackwills avatar Jan 21 '24 21:01 mrjackwills

<currently on fish>
kyllingene@kyllingene ~> sudo echo $SUDO_USER

kyllingene@kyllingene ~> bash
[kyllingene@kyllingene ~]$ sudo echo $SUDO_USER

[kyllingene@kyllingene ~]$

I'm not getting SUDO_USER on either shell, odd.

Could a potential fix for this first check for SUDO_USER, and then fall back to USER?

Perhaps I'm misunderstanding, but I thought the goal was to make dirs::cache_dir et. al. return /root/* (or the equivalent) when running as root? Otherwise the behavior matches what we currently have, which leads to permissions issues.

Kyllingene avatar Jan 23 '24 19:01 Kyllingene

I have the same result with sudo echo $SUDO_USER, but try sudo printenv, that should - well it does for me - list a correct SUDO_USER

mrjackwills avatar Jan 23 '24 19:01 mrjackwills

You are correct. It's quite odd, because even using su gives me nothing:

[kyllingene@kyllingene ~]$ su
[kyllingene kyllingene]# echo $SUDO_USER

[kyllingene kyllingene]#

EDIT: A small test project using std::env::var also returns the proper value.

Kyllingene avatar Jan 26 '24 00:01 Kyllingene

So based on your observations y'all, is there any change that should be discussed?

soc avatar Jan 26 '24 10:01 soc

This issue I was having was that running an application via sudo would return the wrong home dir.

This program is called example

fn main() {
	let home = dirs::home_dir();
	println!("{home:?}")
}

Running ./example, this it prints Some("/home/jack"), but running sudo ./example it instead prints Some("/root").

I, although this may be a mistaken belief, think that both of these executions should return the same result, i.e. Some("/home/jack").

I haven't delved into the code properly, but my assumption was that the SUDO_USER env could help implement this.

mrjackwills avatar Jan 26 '24 10:01 mrjackwills

And now it seems that SUDO_USER is not set as expected? Which, if we used SUDO_USER would lead to different results based on it being there, as far as I understand?

soc avatar Jan 26 '24 11:01 soc

I thought SUDO_USER was set as expected? It just only gets printed by printenv, rather than echo $SUDO_USER

But if not, maybe it could try to use SUDO_USER, and if this fails, fall back to the current implementation?

mrjackwills avatar Jan 26 '24 11:01 mrjackwills

I wonder where the different behavior comes from ...

soc avatar Jan 26 '24 11:01 soc

That I'm not sure, something about variable expansion happening before sudo is executed - which then doesn't inherit the expanded values?

mrjackwills avatar Jan 26 '24 11:01 mrjackwills

SUDO_USER is set properly when using std::env::var, which is all that really matters for this issue.

I'm thoroughly confused at this point. I tested with dirs{,_sys}::{home,cache}_dir, and I got /root and /root/.cache respectively (regardless of whether or not HOME was set). This differs from the behavior in the issue, and seems to me to be the expected behavior?

I, although this may be a mistaken belief, think that both of these executions should return the same result, i.e. Some("/home/jack").

This seems like something dirs-rs should support, but I disagree that it should be the default. If it were, it would lead to problems as described in the original issue (even if I can't reproduce them myself). However, something like user_home_dir could be useful, with documentation clarifying the difference. The trick would be making such a method cross-platform, to which I haven't given much thought yet.

Kyllingene avatar Jan 26 '24 20:01 Kyllingene

Yeah probably a good idea not to replace current behavior, and instead have a new function.

What cross platform issues do you envision? Running the aforementioned example application in Windows, as a normal user, and then as an elevated admin user, results in the same, correct, result each time Some("C:\\Users\\jack").

I don't currently have access to macOS, so sadly can't test on there

mrjackwills avatar Jan 26 '24 20:01 mrjackwills

That's true, Windows doesn't really have the same concepts so the two functions would essentially alias. I don't know what the behavior on Mac would be, perhaps someone here has one they could test on?

Kyllingene avatar Jan 26 '24 22:01 Kyllingene