Problem
I want to know X about currently
logged in/logged on user. There are many variations of this problem. Usually people like to get
user's name, domain
or even credentials.
Solution
What you are asking for doesn't exist and impossible. Try to redesign your application
Explanation
There is no such thing as currently logged in/logged on user.
On NT based systems in general there can
be (and are) many users simultaneously
logged in to a given machine. What you
probably have in mind are interactive
users but even with this clarification
you are out of luck. On NT Terminal
Server, Win2k with terminal services and
plain vanilla XP and later there could
be multiple interactive users at the
same time.
If you suddenly discover that your
application requires knowledge of
"currently logged in user" it means that
you are doing something wrong that
violates OS design. Rather than trying
to outsmart the OS consider redesigning
your application. People often hit this
problem when they are trying to
communicate to the "current user" from a
service. If so you are going in the
wrong direction. Services shouldn't
interact with users. If you have some
information to convey write it to a log
file or an event log.
Back to top
Problem
I want to know X about users logged on to domain.
Solution
Your real problem probably has
a solution but you will have to
reformulate the question to specify what
users you are interested in.
Explanation
There is no such thing as users
logged on to a domain. It is a misnomer
perpetuated by some MS documentation. You always, always log on to a
computer. It could be a terminal you are sitting before or a remote host you
are trying to access files on -- it doesn't matter. You always log on to a
specific machine. Now the question is how the machine knows who you are
(authenticates you). In a simplest pre-network world case it you present
what you claim to be (username) and what you know (password) and the machine
matches this information against it's local database (called SAM database
on Windows). This scheme works as long as you are willing to replicate this
database across all the computers you will ever be likely to access (don't
laugh, some Unix machines are still configured that way). In a networked
world an obvious idea is to centralize this database on some server. This
server becomes a "security authority" (domain controller in Windows lingo)
and it is relied on to perform security related tasks by other machines
(workstations). But now the question is how a specific machine knows which
server to go to and how can it trust this server. Your machine cannot just go to the Internet and use any
server for authentication since you never know whether it belongs to bad-guys.org or good-guys.net :-) Don't forget
that when your machine tries to
authenticate you it may send your password to this server and you do not want
bad-guys.org to know it. There are various ways to solve the trust problem and
Windows developers have chosen that machine administrator must manually
configure which (group of) servers your computer trusts. This operations is
called "joining the domain". After joining your workstation will trust any
of domain controllers in the designated domain to perform security related
tasks for it. When you are "logging into domain" you simply present your
workstation with a set of credentials stored on a domain controller and all
the workstation has to do is to go to DC to validate them. Then it logs you
on locally.
Back to top
Problem
How to find the host from which the
user is logged on.
Solution
There isn't an easy solution to this one. Thought the request is reasonable, Windows
authentication mechanism isn't designed to support this kind of query. The solutions below
may help but they all have many deficiencies. You should consider redesigning your
application instead of relying on them.
All possible solutions can be divided
into two groups: event driven and
polling. Event driven solutions rely on
some kind of notification about user
logon. They have an advantage of seeing
all relevant logons regardless of their
timing. The polling methods rely on
periodic enumeration of some data and
can miss some users. Whether this
matters depends on your goals. All event
driven methods suffer from the logoff
problem which is the fact that in
general there isn't any meaningful
notification about user's logoff (think
what happens when user's machine just)
crashes. Again, this may or may not be a
problem.
Polling solutions
Enumerate CIFS/SMB sessions on the
domain controller
The APIs you need
are:
NetSessionEnum();
NetSessionGetInfo();
One thing to realize here
is that this method
is not even guaranteed to work for all
users logged on now. Recall,
that users do not log on to domain but
to their workstations. Whether this
would result in a network session to a
domain controller is unspecified by MS.
Sometimes it does and sometimes it
doesn't (probably a subject for another
FAQ entry). Again, depending on what
kind of users you are interested in this
method may or may not work for you.
Enumerate terminal services sessions on the machine in question
The APIs you need are:
WTSEnumerateSessions();
WTSQuerySessionInformation();
This method obviously is intended to work with users logged on interactively either locally or
remotely. If this is what you need it is
guaranteed to work. Again, there is a
caveat about not being event driven.
Event-driven solutions
Logon script
Use logon script to run a small application that will
report to some central server about the
fact that user is logged on and the host
on which this happened. The advantage of
this approach is its simplicity. You
don't need to program anything
sophisticated to make it work. The
disadvantages are, however, numerous.
First if most of your users logon at the
same time (say 8:00 AM) you will clog
your network. Second, the mechanism is
unreliable and shouldn't be used for
security. It is too easy for a
workstation user to disable the logon
script. Third, there is a problem
discovering when the user logged off
since you won't necessarily have time to
report it. Finally, and most
importantly, this is not a
shrink-wrapped solution. The nature of
logon scripts is such that each of your
customers will have to do a whole lot of
manual configuration to make it work.
SENS notifications
This solution was suggested by Ivan Brugiolo from Microsoft.
I have never tried to use it and don't
know anybody who did so I'll
just quote his comment here
If you "own" all the machines of the network,
you could use SENS notifications for Logon Events from all the workstations.
If anybody has more information about this method, please let me know
Logon interception on a DC
Intercept all logons on the domain controller by hooking
LsaApLogonUser[Ex|Ex2]();
in MSV1_0 authentication package. As
you can see from the documentation on of
the parameters of the above API's
contains the name of the machine from
which the logon is made. This method is very
powerful but, unfortunately, it is
limited to old-style (NT) domains only.
New Win2k style domains that use
Kerberos authentication do not pass this
information. In fact if you look on your
Win2k domain DC security event log you
will notice that all logon events are
missing machine name too. Apparently,
Windows itself doesn't know. If you
decide to use this method you will need
to inject your code into lsass.exe (Local
Security Authority SubSystem)
process. If you do so make sure you give
your users a way to disable your
software in boot sequence. If you crash
lsass.exe the system will die and there
is nothing the users will be able to do.
Explanation
This is not really an explanation but a gripe about the way Microsoft implemented
its authentication mechanism. The
request to know the host from which the
authentication was performed is a
natural one, especially in security
applications, and there should be a
simple way to do it.
Back to top
Problem
I have two domains A and B. My account in
both domains is Bob and has the same password. I've noticed that when I am logged
on on a machine A1 in domain A as A\Bob
and try to access machine B1 in domain B
I am not prompted for credentials and
silently authenticated as B\Bob. What is
going on? Is this normal?
Explantion
Yes it is normal and documented behavior. More details are
here.
Make sure you read the last section in
this article.
Explantion
While I don't know the precise reasons for this feature I can speculate
that this is a
- Legacy of old pre-domain
Windows networks.
- A way to make ad-hoc networks of
NT-based workstations work.
The legacy argument goes like this.
In the old days all
you had was username as there was no
concept of domains. When an old style
Windows/Lan Manager client connects to a share it
probably sends only the username "Bob"
without the domain. A modern server must somehow make sense
of such request by assuming that the
client belongs to the same domain and
trying its username and password.
The second argument is that many
people (especially home users and small
businesses) create ad-hoc networks of
NT-based computers with same account
names and passwords on all machines. It
would be very inconvenient for them if
every access to a share resulted in a
logon box. One could imagine a user
shouting "why couldn't stupid Windows
figure out that I am Bob?". So it does
Back to top