QStandardPaths corresponding to a different user on Linux
-
@Paul-Colby @SGaist , thank you for the advice to use sudo and the pointer to the source code.
I do not have an XDG_CACHE_HOME environment variable, so HOME is what is being used.
I discovered that "sudo -u user01 -i env | grep HOME" returns:
HOME=/home/user01
whereas "sudo -u user01 -i echo $HOME" returns:
/root
(and indeed, getenv("HOME") inside the program, after switching uid/euid, also returns /root)
So, it is not a Qt specific issue after all. Thanks for helping me figure this out!
-
@mbrochmann
Your issue seems to be to do with fetching the value of environment variables to return certain values. Let's be clear:setuid
/seteuid
, orchmod ug+s
, affect permissions but do nothing toward altering the environment under which a program runs.I don't think you'll be able to retrieve the user-specific paths/variables for another user without logging in (including via
sudo
) as that user to allow the environment to be set up appropriately. -
@mbrochmann said in QStandardPaths corresponding to a different user on Linux:
whereas "sudo -u user01 -i echo $HOME" returns:
/rootThis is because the
$HOME
is being expanded beforesudo
is run. Compare, for example:root@paul-XPS-13-9343:~# sudo -u paul -i echo $HOME /root root@paul-XPS-13-9343:~# sudo -u paul -i echo "$HOME" /root root@paul-XPS-13-9343:~# sudo -u paul -i echo '$HOME' /home/paul root@paul-XPS-13-9343:~#
@JonB said:
I don't think you'll be able to retrieve the user-specific paths/variables for another user without logging in (including via
sudo
) as that user to allow the environment to be set up appropriately.You can get the path other ways, and then either use the path directly, or set the environment manually. For example, if you can't control the code, but you know that it uses
QStandardPath
, you can use shell expansion, across users, eg:paul@paul-XPS-13-9343:~/src/extern/forum-qt-io$ ./foo "/home/paul/.local/share" paul@paul-XPS-13-9343:~/src/extern/forum-qt-io$ HOME=~alice ./foo "/home/alice/.local/share"
(here my
foo
application just does:qDebug() << QStandardPaths::writableLocation( QStandardPaths::GenericDataLocation);
)You can also use
getent
, such as:paul@paul-XPS-13-9343:~/src/extern/forum-qt-io$ HOME=`getent passwd alice | cut -d: -f6` ./foo "/home/alice/.local/share"
If you can control the code, then you can either execute
getent
or parse/etc/passwd
directly (for legacy reasons this is always world-readable), then you can set the environment from within your code. eg:qDebug() << "before" << QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); QFile file("/etc/passwd"); file.open(QFile::ReadOnly); while (file.isOpen() && !file.atEnd()) { auto entry = file.readLine().split(':'); if ((entry.size() > 5) && (entry.at(0) == "alice")) { qputenv("HOME", entry.at(5)); file.close(); // Just to shortcut the loop. } } qDebug() << "after" << QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
Which outputs (for me):
before "/home/paul/.local/share" after "/home/alice/.local/share"
Of course, none of this is portable to other platforms.
Cheers.
-
@Paul-Colby
You cannot get theQStandardPaths
for another user.If I understand you rightly, you are saying that you know for example to parse
/etc/passwd
for stuff which you will use to do some work. But that only works if you know just what the code forQStandardPaths
is doing, presumably by examining the source code for each "variable" you might be interested in. Personally I would not want to do that. -
@JonB said in QStandardPaths corresponding to a different user on Linux:
You cannot get the QStandardPaths for another user.
You can on most Linuxes, which is the platform the subject specifically asked for. It's not portable, and like you I would try to avoid it, but if its solves the OP's need, and the limitations are understood, then it might be their best, if not only option.
Cheers.
-
@Paul-Colby said in QStandardPaths corresponding to a different user on Linux:
This is because the $HOME is being expanded before sudo is run. Compare, for example:
root@paul-XPS-13-9343:~# sudo -u paul -i echo $HOME
/root
root@paul-XPS-13-9343:~# sudo -u paul -i echo "$HOME"
/root
root@paul-XPS-13-9343:~# sudo -u paul -i echo '$HOME'
/home/paulI had not considered that, thanks for the explanation!
Nevertheless, as @JonB pointed out, seteuid won't result in getenv returning what I want.
I decided to go with
getpwuid( geteuid() )->pw_dir;
Short/sweet, gets me what I want. :)
I really feel like QStandardPaths should consider the euid on Linux, but I might be biased by my current coding goals. :)
-
"You cannot get the QStandardPaths for another user."
It may be worth pointing out that on Windows this can be done using "ImpersonateLoggedOnUser" and associated functions.
-
@mbrochmann
To the best of my knowledge, to useImpersonateLoggedOnUser
you need a handle to an impersonation access token (https://msdn.microsoft.com/en-us/library/windows/desktop/aa378612(v=vs.85).aspx), and that can only be obtained fromLogonUser
or similar. Which requires the user's password. Unless you know of another relevant way, which I'd be very interested to learn of?I don't see how this would work in the context the OP is asking about, and the Linux setuid approach. He needs some way of discovering other users' paths without them having to log on or give him their password!
-
Yes, this only works if the caller has sufficient privilege to get a process handle (via OpenProcess) with impersonation privileges - but no explicit password needs to be passed in this case.
It's probably overkill for most situations, but I just wanted to point out that if this has been done, QStandardPaths will behave as if in the context of the impersonated user.
-
@mbrochmann
Yes --- but just so I understand, if you don't mind --- theOpenProcess
for obtaining the handle can only be of a process already running by the user you want to impersonate. That user had to log in, or supply his password, to get to that state in the first place. That's all you can do under Windows, right? The OP wants to be able to impersonate some random, non-logged-in user for this purpose, which you can do with Linux'ssetuid(uid)
, but you cannot in Windows, is that right? -
Yes, the impersonated user must be logged in and running a process - I am the original poster, and it is indeed a very specific situation.
There is probably a much easier way to get a user's home directory on Windows, but we were already impersonating the user for other reasons. :)
-
@mbrochmann Did you ever figure out a solution to this?