I want to have a service (or a regular program, it doesn't matter to me)
that will start another process under
the System Account.
Here's what I have encountered:
When I have my program running as a service under the system account, the
LogonUser call gets an access violation. More correctly and application
error.
"The instruction at "0x77dc670b" referenced memory at "0x00000000". The
memory could not be "written".
Now, it just so happens that I set my "handle" to 0 before I did the
LogonUser call. Before, when I had not initalized that pointer at all, the
referenced memory just so happened to be equal to whatever the pointer was
before that too.
before you start telling me my code is messed up (although it OBVIOUSLY is),
When I had my program running as a service under MY account, the LogonUser
command did NOT cause
an access violation. Instead, it returned at 203 error, which is
203 The system could not find the environment option that was entered.
ERROR_ENVVAR_NOT_FOUND
Which means nothing to me.
I haven't even GOT to the ImpersonateLoggedOnUser or CreateProcess calls.
My questions are (so far), what does the 203 mean? How do I "log on" as the
System Account (without being a service)? What's the user ID and password.
And for that matter, what's the domain?
Am I doing something VERY fundamentally wrong here?
Here's my sample code.
void ControlMain(int arg_count, char *argv[], char *envp[])
{
DWORD error;
BOOL yes;
PHANDLE handle;
STARTUPINFO si; /* for CreateProcess call */
PROCESS_INFORMATION pi; /* for CreateProcess call */
handle = 0;
yes = LogonUser("user", "domain", "password",
LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, handle);
error = GetLastError();
yes = ImpersonateLoggedOnUser(handle);
error = GetLastError();
yes = CreateProcess("notepad.exe", /* filename */
NULL, /* command line or full path line */
NULL, /* process security descriptor */
NULL, /* thread security descriptor */
FALSE, /* inherit handles? */
0, /* creation flags */
NULL, /* inherited environment address */
NULL, /* startup dir; NULL = start in current */
&si, /* pointer to startup info (input) */
&pi); /* pointer to process info (output) */
error = GetLastError();
yes = RevertToSelf();
> Am I doing something VERY fundamentally wrong here?
A kind of...
> PHANDLE handle;
> handle = 0;
>
> yes = LogonUser("user", "domain", "password",
> LOGON32_LOGON_BATCH, LOGON32_PROVIDER_DEFAULT, handle);
LogonUser() needs PHANDLE not because it just has fun with PHANDLEs, but
merely to *STORE* the real handle to the location pointed by that PHANDLE.
It can't store the handle at zero address, nor it should store the handle at
an arbitrary memory location where the pointer just happens err... to point
to. Just provide some place for storing.
HANDLE token;
LogonUser(..., &token);
Note the last argument, it is the address of a var that is capable of
containing a handle.
> yes = ImpersonateLoggedOnUser(handle);
>
> error = GetLastError();
>
> yes = CreateProcess("notepad.exe", /* filename */
> NULL, /* command line or full path line */
> NULL, /* process security descriptor */
> NULL, /* thread security descriptor */
> FALSE, /* inherit handles? */
> 0, /* creation flags */
> NULL, /* inherited environment address */
> NULL, /* startup dir; NULL = start in current */
> &si, /* pointer to startup info (input) */
> &pi); /* pointer to process info (output) */
>
This won't start the process in the context of the user logged on by
LogonUser(). It will always start it in the context of the user *this*
process has been running under initially. User CreateProcessAsUser() for
your task. And, of course, Impersonate...() and RevertToSelf() are not
necessary.
-- Slava
Please send any replies to this newsgroup.
Aiiiigh! We can stop here, please. :) I don't mean for this to be
critical at all (I have walked in your shoes), but this is a basic point
of th Windows API (and of C/C++ functions in general, pretty much), and
it's very important that you understand what's wrong here, not just how to
fix it in this particular case.
That last parameter to LogonUser is a PHANDLE--in other words, a pointer
to a HANDLE. As the documentation says, this parameter should be a "Pointer
to a HANDLE variable that receives a handle to a token that represents the
selected user." In other words, LogonUser expects that you've already created
a HANDLE variable somewhere, and that you're passing in a pointer to that
HANDLE you've created--something like this:
HANDLE hToken;
yes = LogonUser("user","domain","passwd",LOGON32_LOGON_BATCH,
LOGON32_PROVIDER_DEFAULT,&hToken);
// hToken now has the handle to the user's token
You're not doing that; you're passing in a pointer with a value of 0.
By doing that, you're telling LogonUser, "Location 0 in memory is a HANDLE
variable; write the user's token handle there." It proceeds to try to do
just that. But location 0 most certainly doesn't have a HANDLE variable;
in fact, your program doesn't have the right to put anything in location 0
at all. So the program crashes.
Whenever a function deals with pointers like this, unless the
documentation for a function specifically says "I'll create this memory
object for you", you should almost always assume that it doesn't--that you
have to have already created the memory objects that the function will use,
and pass in the address of those objects.
--
\o\ If you're interested in books and stories with transformation themes, \o\
/o/ please have a look at <URL:http://www.halcyon.com/phaedrus>. Thanks! /o/
\o\ FC1.21:FC(W/C)p6arw A- C->++ D>++ H+ M>+ P R T++++ W** Z+ Sm RLCT \o\
/o/ a cmn++++$ d e++ f+++ h- i++wf p-- sm# /o/
Granted, and I did that and I don't ABORT any more. But there is a question
regarding that. WHY did I abort when I ran this service from the "system
account", but NOT my user account?
So, it doesn't abort anymore, but what is this 203 error I'm getting?
>
>This won't start the process in the context of the user logged on by
>LogonUser(). It will always start it in the context of the user *this*
>process has been running under initially. User CreateProcessAsUser() for
>your task. And, of course, Impersonate...() and RevertToSelf() are not
>necessary.
What's the point of Impersonate then? Anyway, what I REALL want to do is
run a service under the System Account that starts a program under the
System Account. I imagine, that in that case, I wouldn't have to LogonUser
at all, correct?
So what is the 203 error?
Thanks,
Jeff.
>
> Granted, and I did that and I don't ABORT any more. But there is a
question
> regarding that. WHY did I abort when I ran this service from the "system
> account", but NOT my user account?
>
> So, it doesn't abort anymore, but what is this 203 error I'm getting?
Sorry, you mean that you ARE getting the error NOW that you fixed the call?
It may fail when called from a user account because the user may not have
SeTcbName privilege, but I guess you will get some other error code...
> What's the point of Impersonate then?
Impersonate*() only allows the thread that calls it to do stuff as it were
the user being impersonated, with the exception of starting new processes.
OK, it is more convoluted than that, but here goes:
1. Each process has a primary token, this is the token of the user that
started the process.
2. Each thread may have a thread token, which may be different from the
primary token. When a thread tries to access a resource, system first checks
the thread token, or if does not exist, it checks the primary token. When
you call Impersonate*() functions, they replace the thread token with the
token of the user being impersonated. When you call RevertToSelf(), the
thread drops the thread token and runs with the primary one.
Now, CreateProcess() call ALWAYS uses the primary one to start new
processes, while CreateProcessAsUser() lets you specify which one to use.
The token used to start new process then becomes the primary token of the
new process.
> Anyway, what I REALL want to do is
> run a service under the System Account that starts a program under the
> System Account. I imagine, that in that case, I wouldn't have to
LogonUser
> at all, correct?
Right.
> So what is the 203 error?
<g> I wish I knew...
Yes. Actually, I ALWAYS got that error.
>It may fail when called from a user account because the user may not have
>SeTcbName privilege, but I guess you will get some other error code...
Nope. Different error. 203 is
203 The system could not find the environment option that was entered.
ERROR_ENVVAR_NOT_FOUND
But it makes no sense to me. Also, this program that I want to start will
start, do it's thing, and get out. No intereaction with the desktop, etc.
What do I have to supplu in the STARTUPINFO sctructure?
Thanks,
jeff
> >> So, it doesn't abort anymore, but what is this 203 error I'm getting?
> >
> >Sorry, you mean that you ARE getting the error NOW that you fixed the
call?
>
> Yes. Actually, I ALWAYS got that error.
Have you tried calling LogonUser with NULL domain name? Also, are you sure
that the user you're trying to log on has "Log on as Batch Job" privilege
(check with User Manager, advanced rights).
> Nope. Different error. 203 is
I know, I know. To me this is as frustrating as to you.
> But it makes no sense to me. Also, this program that I want to start will
> start, do it's thing, and get out. No intereaction with the desktop, etc.
> What do I have to supplu in the STARTUPINFO sctructure?
If you're going to execute a program from system context to be running in
the system context again, you don't have to call any LogonUser(); the
easiest way to prepare the STARTUPIBFO struct is by calling
GetStartupInfo(). Or do you have any additional considerations?