Get logged in username from script launched by launchdeamon - macos

I am trying to find the current (logged in) users name. The script looks for a particular user and changes the network configuration.
The script is started by a LaunchDeamon in /Library/LaunchDeamons.
I am not able to find a way to get the users name who is logging, so if I login as Tom when I call the script the username is root.
Can one one suggest a way to get Tom?

A LaunchDaemon is a system process. It may run when no one is logged in. If you want something that runs in a user's context, you likely want a LaunchAgent instead.
Note that "the current (logged in) user" is somewhat poorly defined because there may be fast user switching (so multiple logged in users), and users may login without a GUI session (via SSH for instance). If you use a LaunchAgent, there may be multiple copies running (and if no user is logged in, there may be no copies running).
For your example, you may just be looking to fetch current login session information (though remember, if you're a LaunchDaemon, then there may be no login session currently). This is best described in Multiple User Environment Programming Topics. In particular, look at "Getting Login Session Information."
In some cases it may be preferable to let a central system daemon communicate with per-session agents. One easy technique for that is NSDistributedNotification, particularly if data only needs to go in one direction. If you need more complex interactions between a system daemon and the user sessions, you should investigate XPC services, which are designed for that kind of problem. See "Creating XPC Services" in the Daemons and Service Programming Guide.
System-level programming, especially things involving user sessions, is exceedingly subtle on OS X (particularly compared to Linux). You should study the Daemons and Services Programming Guide carefully before undertaking it. Things that sound very simple turn out to have many corner cases and surprises. Fast user switching, non-local accounts, mounted home directories, privilege separation (particularly post-10.7), the incredibly vagaries of launchd.... It's all quite manageable, but definitely important to spend some study time before diving in.

OS X allows multiple users to be logged in at the same time. If you are trying to get the name of active console user, the script given below might help.
LOGGED_IN_USER=`stat -f%Su /dev/console`

You cannot as launch daemon runs in the system context and not user context.
As per Apple:
Most daemons run in the system context of the system—that is, they run at the lowest level of the system and make their services available to all user sessions. Daemons at this level continue running even when no users are logged into the system, so the daemon program should have no direct knowledge of users. Instead, the daemon must wait for a user program to contact it and make a request. As part of that request, the user program usually tells the daemon how to return any results.

Related

What's "Replace a process level token" for anyway?

Let me start by saying I know next to zero about Windows. My understanding is that processes in Windows get their privileges from a process-level token, which normally would identify the user started the process, but may differ as is common for system tasks, correct? This is somewhat akin to Linux processes having real and effective user and group IDs (it may not be appropriate to make analogies to Linux, but it's all I know). Also, as far as I know, a user can run a process as another user using runas.exe (similar to sudo in Linux). And of course they'll be prompted for the credentials of the user they want to run the process as, and as long as they know the credentials no special permissions are needed, correct?
Now, there is a user right called "Replace a process level token", which according to the docs:
Users with the Replace a process level token user right can start processes as another user if they know the user’s credentials.
Emphasis above is mine. So my question is: if someone knows the credentials for a given user, they can always run a process as them (either using runas.exe or just by logging in as them). What's the purpose of the "Replace a process level token" user right, and what's the security impact of it?

Ways to find out if the process is created by system (by pid) on macOS?

I'm implementing API which allows to launch other apps (using NSTask) inside VFS (FUSE on macOS). After VFS is mounted a bunch of processes start accessing launched VFS in which my app works, and I'd like to implement some kind of filtering mechnism which will allow to detect whether process which is accessing the VFS is created by system (and potentially safe) or not, and if so it'll be granted an access to the file system where my app runs.
So far I'm able to get basic information of the process by it's pid. For example: process path, uid, ppid, code signature of the process etc (using Security framework, libproc etc)
I've done a couple of tests and see that there are process with uid != 0 and still critical for my app to run (if I deny access to them app which is started in VFS crashes) (e.g. /usr/libexec/secinitd, /System/Library/CoreServices/Dock.app/Contents/MacOS/Dock), so looks like approach with filtering processes by pids, uids, ppids might not work.
So the question is: is it possible to distinguish whether process which is accessing my app was created by system and is potentially safe? I also don't want to do too much work by denying accees to critical system processes which will allow the app to successfully start and run in VFS.
Judging from the comment thread, your threat model is data theft via malware etc.
In this case, you can trust almost nothing, so the best way is probably to maintain an explicit whitelist of processes which are allowed to access your mount point, and block access to everything else by default. Log any processes to which access is denied, and allow the user to reverse that decision and add them to the whitelist. In other words, let the user decide what applications they consider safe.
Your said that according to your inspection, there were several processes which were mandatory for the process to run, so why won't use try-and-error approach.
You deploy you FUSE drive on clean environment and record all processes that attempt to access your files - try to prevent each process and keep only those which crash your apps, and add them to a white-list.
Of course that this list is subject to change in different macOS versions, but it can give you the general idea.
Alternatively, you can break your app into couple of parts. for example, put the sensitive logic inside separated dylib file, and prevent access to this file only.. since dylib is not the main executable in your app, I believe fewer processes require mandatory access it.

Impersonating a user on Mac OS X

On Windows it is possible to have a service that allows clients running in a user context to connect to it using sockets or pipes, and then impersonate the connecting user in order to act on behalf of that user, for instance to access files that only the user has access to (or making sure that no other files are accessed).
What is the equivalent way of accomplishing this on Mac OS X (Linux is interesting too)? I would assume that the set*uid functions would be used for this in some way?
But how do I authenticate the user that I want to impersonate and get the uid to set when the user is connecting on a socket?
Also, the set*uid functions seem to affect the entire process, which makes them difficult to use in a multithreaded daemon. Is there a different commonly used design pattern for this type of services on Mac OS X/Linux?
Edit:
pmjordan's answer seems to take care of the set*uid per-process-only issue, and the question How can I pass user credentials through a Unix-domain socket on Mac OS X? seems to take care of the actual authentication problem by using unix domain sockets instead of plain sockets.
For OS X specifics: have you looked at the Authentication, Authorization, and Permissions Guide for Mac OS X?
Generally, in UNIX-like operating systems, processes typically are owned by one specific user, and what they are permitted to do is determined primarily by this. There are some exceptions to this, but generally, the idea tends to be to do this on a per-process granularity. On the plus side, starting new processes is really easy - see the fork() function.
So a typical way for a daemon (such as sshd) to impersonate different users is to run the main process as root. Then, accept incoming connections and pass them off to fork()ed child processes, which, as you say, immediately drop privileges using set*uid. There are various inter-process communication channels, such as pipes, that you can set up if the child processes need to communicate with the parent process. Obviously, the less code runs as root, the better, from a security perspective, so you'll want to aim for the child processes to be autonomous.
If you need users to actually provide their username and password, things get a bit more complicated; you might want to look at the source code for the su and sudo utilities, and read the platform-specific documentation for authentication APIs.
from Technical Note TN2083 - Apple Developer
In some cases it is helpful to impersonate the user, at least as far as the permissions checking done by the BSD subsystem of the kernel. A single-threaded daemon can do this using seteuid and setegid. These set the effective user and group ID of the process as a whole. This will cause problems if your daemon is using multiple threads to handle requests from different users. In that case you can set the effective user and group ID of a thread using pthread_setugid_np. This was introduced in Mac OS X 10.4.

How can I autostart a UI-application under windows that a non-admin user cannot close?

I have developed a C# Windows Forms application that runs in the background as a systray icon and does some stuff when it's clicked. It is supposed to launch when Windows starts and run continously, and a normal user without administrator rights shall not be allowed to shut it down.
What is the best way to do this? I initially intended to run it on the LocalSystem account through Task Scheduler, but then I learned (the hard way) about Session 0 isolation (i.e. the application will run but its UI elements do not show). When I run it with the logged in user, even if it runs elevated, the user can still shut it down through task manager (without requiring elevation).
Is there any way to give a process from LocalSystem access to the UI? I have a winlogon and a csrss process from LocalSystem running in session 1, so I guess it can be done, I just don't know how. Or is there maybe an easier way to disallow users to shut down a process of their own through the task manager? The only other option I can think of is to create an extra Windows Service that keeps polling if the app is running, and immediately launches it again if someone kills it - but that seems incredibly clumsy (also, I want it to stay dead when it crashed by itself, to avoid a single bug causing infinite loops of process creation).
Deponds on why they can't shut it down.
The natural way to go would to have created a service, started by a high priv account, and then had the desktop app just show what it was doing.
If there's something that they should see, but don't becasue they aren't running the service monitor app. (and acknowledge message back to the service), send them an email, send their boss an email, send yourself one and then go shout at them.....
Be a lot easier than trying to get the lid back on this tin of worms.
A nice way to make sure the desktop app is ruuning, would be simply to schedule it to run every X, but drop out immediately if it already is or the somethingwenthorriblywrong flkag is set.
Not worth writing a service to check if it's still there, as they could kill that as well, unless you want to make that a service they can't kill. :(
You are trying to be too draconian with this. Add some sort of auditing so you can see it dies or was shutdown, monitor that and deal with any adverse reports. It's a heck of a lot easier, and gives manage something to do...
You can run an administrative process in the user's logon session. One method would be to for a master process (a system service) to duplicate its own token, use SetTokenInformation to change the session associated with the token, and then call CreateProcessAsUser. The lpStartupInfo parameter can be used to associate the process with a particular window station and desktop. It may be necessary to explicitly change the permissions on the window station and desktop first.
HOWEVER, this is a bad idea from a security standpoint, because GUI applications are vulnerable to malicious messages sent from other processes on the same desktop ("shatter attacks").
It would be safer to run the process in the user's own context but apply an ACL to it. This can be done using the lpProcessAttributes parameter to CreateProcess or CreateProcessAsUser, or with the SetSecurityInfo function. I've never tried this, but it should in theory prevent the user from using task manager to close the process.
If you are creating the process from the user's context, then the user will be the owner, so a sufficiently knowledgeable person could change the permissions back in order to terminate the process. If you need to block this hole, using CreateProcessAsUser from a privileged master process (the token can be duplicated from one of the existing processes in the user's session) should (again, in theory) mean that the user is not the process owner.
Another potential issue: if you listen for messages indicating that the user is logging out (in order to exit) such a message could be faked. If you don't then you need to find some other way of exiting when the user logs out. You may need to experiment here, I'm not sure how the system will react.

Is there a way to have multiple windows logins go to single session?

In windows 7, is there a way to have every login go to the same user session. So when a person is met with the login screen, they login and can continue working on that same user session. I am asking this because each user has their own login, but on this machine I need a program to be running across all user sessions. Since that doesn't seem feasible, I was just going to have them all login to the same user session.
Is this possible?
The appropriate way to solve this would be to have the program run as a service, and have a client UI that loads on startup 'hook' into the service process. Loading multiple users to the same session space would effectively violate the entire windows security model.
So, you either need to use a shared user for this, or a shared process (either local as a service, or remote as a server)
So, there's one possible way you might be able to get this to work, and that's to set this up as an interactive service. Definitely not a secure way to keep your system, but if you are able to make it work, it should work for your purposes:
Interactive services (in particular, read 'using an interactive service'):
http://msdn.microsoft.com/en-us/library/windows/desktop/ms683502(v=vs.85).aspx
Making srvany.exe (to run non-services as a service) on Windows7/Windows 2008:
http://social.technet.microsoft.com/Forums/en-US/winserverMigration/thread/98a97aee-c62b-4683-94ab-3777899cf7de/

Resources