How to execute a process under another account - PROPERLY?



Hello,

Our application runs as a service under Windows 2000/XP/2003 in the local
system account. It must execute another program to automatically print a
report in emergency situations. The printer(s) are typically located
elsewhere on the network and not accessible from the local system account. I
therefore implemented an option to execute the report writer in another
account. Problem is, it does not work consistently for all our customers
when executed this way, even though it invariably works fine when you log on
to the machine "normally" using the other account and run the report writer.
Can someone point me to a definitive, up-to-date sample program or
documentation on how to programmatically execute a program in another
account, where the logon behaves EXACTLY, to the last detail, as if the user
had interactively logged on to the machine? I am so far using the following
functions:

NetUserGetInfo () - to get roaming user profile path, if necessary
LogonUser () - to get token required by calls below
LoadUserProfile () - to load HKEY_LOCAL_USER registry hive
CreateEnvironmentBlock () - to create user's environment
ImpersonateLoggedOnUser () - to be able to execute program via other users
file permissions
CreateProcessAsUser () or alternatively CreateProcessWithLogon ()

I have seen an example where the programmer was manipulating access lists
and DACLs (sorry if I misspell or for misnomers - I'm out of my depth here),
but that appeared to be for Windows NT. Is it necessary to go down to that
"depth"?

Here is an excerpt of the code I'm using:

if (running_as_service && *settings->roll_call.windows_user)
{
char windows_user [sizeof
settings->roll_call.windows_user];
char profile_path [0x200];
CreateProcessWithLogonFunc create_process_with_logon;
CreateProcessAsUserFunc create_process_as_user;
LogonUserFunc logon_user;
CreateEnvironmentBlockFunc create_environment_block;
DestroyEnvironmentBlockFunc destroy_environment_block;
LoadUserProfileFunc load_user_profile;
UnloadUserProfileFunc unload_user_profile;
ImpersonateLoggedOnUserFunc impersonate_logged_on_user;
RevertToSelfFunc revert_to_self;
PROFILEINFO profile_info;
void *environment;
HMODULE net_module;
HMODULE module;
HANDLE token;
STARTUPINFOW infow;
BOOL rc;

if (! (module = GetModuleHandle ("advapi32.dll")))
{
error = true;
sprintf (error_message, "Can't execute %.30s..., unable to load
advapi32.dll: %s", string, get_system_error_message ());
blog->write (LOG_ERROR, 808, "%s", error_message);
goto OPEN_DOORS;
}

if (! get_function (module, "CreateProcessWithLogonW", (FARPROC)
create_process_with_logon, error_message, error, string))
goto OPEN_DOORS;

if (! get_function (module, "CreateProcessAsUserA", (FARPROC)
create_process_as_user, error_message, error, string))
goto OPEN_DOORS;

if (! get_function (module, "LogonUserA", (FARPROC) logon_user,
error_message, error, string))
goto OPEN_DOORS;

if (! get_function (module, "ImpersonateLoggedOnUser", (FARPROC)
impersonate_logged_on_user, error_message, error, string))
goto OPEN_DOORS;

if (! get_function (module, "RevertToSelf", (FARPROC)
revert_to_self, error_message, error, string))
goto OPEN_DOORS;

if (! (module = LoadLibrary ("userenv.dll")))
{
error = true;
sprintf (error_message, "Can't execute %.30s..., unable to load
userenv.dll: %s", string, get_system_error_message ());
blog->write (LOG_ERROR, 808, "%s", error_message);
goto OPEN_DOORS;
}

if (! get_function (module, "CreateEnvironmentBlock", (FARPROC)
create_environment_block, error_message, error, string))
{
FreeLibrary (module);
goto OPEN_DOORS;
}

if (! get_function (module, "DestroyEnvironmentBlock", (FARPROC)
destroy_environment_block, error_message, error, string))
{
FreeLibrary (module);
goto OPEN_DOORS;
}

if (! get_function (module, "LoadUserProfileA", (FARPROC)
load_user_profile, error_message, error, string))
{
FreeLibrary (module);
goto OPEN_DOORS;
}

if (! get_function (module, "UnloadUserProfile", (FARPROC)
unload_user_profile, error_message, error, string))
{
FreeLibrary (module);
goto OPEN_DOORS;
}

*profile_path = EOS;

if (settings->roll_call.support_roaming_profiles)
if (net_module = LoadLibrary ("netapi32.dll"))
{
char user_and_domain [sizeof
settings->roll_call.windows_user + sizeof
settings->roll_call.windows_domain];
wchar_t windows_user [0x60];
USER_INFO_3 *user_info_3 = NULL;
NetApiBufferFreeFunc net_api_buffer_free;
NetUserGetInfoFunc net_user_get_info;
int len;
NET_API_STATUS rc;

if ((net_user_get_info = (NetUserGetInfoFunc) GetProcAddress
(net_module, "NetUserGetInfo")) &&
(net_api_buffer_free = (NetApiBufferFreeFunc)
GetProcAddress (net_module, "NetApiBufferFree")))
{
if (*settings->roll_call.windows_domain)
sprintf (user_and_domain, "%s\\%s",
settings->roll_call.windows_domain, settings->roll_call.windows_user);
else
strcpy (user_and_domain,
settings->roll_call.windows_user);

MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED,
user_and_domain, -1, windows_user, sizeof windows_user / sizeof (wchar_t));

switch (rc = net_user_get_info (NULL, windows_user, 3,
&user_info_3))
{
case NERR_Success:
if (user_info_3 && user_info_3->usri3_profile)
if (0 < (len = WideCharToMultiByte (CP_ACP,
WC_SEPCHARS, user_info_3->usri3_profile, -1, profile_path, sizeof
profile_path, NULL, NULL)))
profile_path [minimum ((size_t) len, sizeof
profile_path - 1)] = EOS;
else
*profile_path = EOS;

break;

case ERROR_ACCESS_DENIED:
blog->write (LOG_INFO, 811, "NetUserGetInfo (%s):
Access Denied", user_and_domain);
break;

case NERR_InvalidComputer:
blog->write (LOG_INFO, 811, "NetUserGetInfo (%s):
Invalid Computer", user_and_domain);
break;

case NERR_UserNotFound:
blog->write (LOG_INFO, 811, "NetUserGetInfo (%s):
User Not Found", user_and_domain);
break;

default:
blog->write (LOG_INFO, 811, "NetUserGetInfo (%s):
%d", user_and_domain, rc);
break;
}

if (user_info_3)
net_api_buffer_free (user_info_3);
}
else
blog->write (LOG_INFO, 811, "NetUserGetInfo () or
NetApiBufferFree () is not available: %s", get_system_error_message ());

FreeLibrary (net_module);
}
else
blog->write (LOG_INFO, 811, "Unable to load netapi32.dll:
%s", get_system_error_message ());

if (! settings->roll_call.create_process_with_token ||
settings->roll_call.load_user_profile ||
settings->roll_call.load_environment ||
settings->roll_call.impersonate_user)
{
if (! logon_user (settings->roll_call.windows_user,
settings->roll_call.windows_domain,
settings->roll_call.windows_password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&token))
{
error = true;
sprintf (error_message, "Can't execute %.30s..., unable to
log on: %s", string, get_system_error_message ());
blog->write (LOG_ERROR, 808, "%s", error_message);
FreeLibrary (module);
goto OPEN_DOORS;
}
}
else
token = INVALID_HANDLE_VALUE;

str_ncpy (windows_user, settings->roll_call.windows_user, sizeof
windows_user);
memset (&profile_info, 0, sizeof profile_info);
profile_info.dwSize = sizeof profile_info;
profile_info.lpUserName = windows_user;

if (*profile_path)
profile_info.lpProfilePath = profile_path;

if (settings->roll_call.load_user_profile)
{
rc = load_user_profile (token, &profile_info);

if (! rc)
blog->write (LOG_WARNING, 810, "Unable to load user profile:
%s", get_system_error_message ());
else
{
verify (rc != ERROR_INVALID_PARAMETER);
}
}

if (settings->roll_call.load_environment)
if (! create_environment_block (&environment, token, FALSE))
{
blog->write (LOG_WARNING, 810, "Unable to create environment:
%s", get_system_error_message ());
environment = NULL;
}
else
environment = NULL;

if (settings->roll_call.impersonate_user)
if (! impersonate_logged_on_user (token))
blog->write (LOG_WARNING, 810, "Unable to impersonate user:
%s", get_system_error_message ());

memset (&infow, 0, sizeof infow);
infow.cb = sizeof infow;

if (settings->roll_call.create_process_with_token)
{
wchar_t windows_user [0x40];
wchar_t windows_password [0x40];
wchar_t windows_domain [0x40];
wchar_t command_line [0x500];
wchar_t core_forms_path [0x120];

MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED,
settings->roll_call.windows_user, -1, windows_user, sizeof
windows_user / sizeof (wchar_t));
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED,
settings->roll_call.windows_password, -1, windows_password, sizeof
windows_password / sizeof (wchar_t));
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED,
settings->roll_call.windows_domain, -1, windows_domain, sizeof
windows_domain / sizeof (wchar_t));
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED,
-1, command_line, sizeof command_line / sizeof (wchar_t));
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED,
settings->core_forms_path, -1, core_forms_path, sizeof
core_forms_path / sizeof (wchar_t));

if (create_process_with_logon (
windows_user,
windows_domain,
windows_password,
0x01,
0,
command_line,
CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE |
CREATE_NEW_PROCESS_GROUP | (environment ? CREATE_UNICODE_ENVIRONMENT : 0),
environment,
core_forms_path,
&infow,
&pi))
{
CloseHandle (pi.hThread);
CloseHandle (pi.hProcess);

if (settings->roll_call.impersonate_user)
revert_to_self ();
}
else
{
if (settings->roll_call.impersonate_user)
revert_to_self ();

sprintf (error_message, "Can't execute %.30s...: %s", string,
get_system_error_message ());
blog->write (LOG_ERROR, 809, "%s", error_message);
error = true;
}
}
else
if (create_process_as_user (token, NULL, string, NULL, NULL,
FALSE,
CREATE_NEW_CONSOLE |
CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP | (environment ?
CREATE_UNICODE_ENVIRONMENT : 0),
environment,
settings->core_forms_path, &info, &pi))
{
CloseHandle (pi.hThread);
CloseHandle (pi.hProcess);

if (settings->roll_call.impersonate_user)
revert_to_self ();
}
else
{
if (settings->roll_call.impersonate_user)
revert_to_self ();

sprintf (error_message, "Can't execute %.30s...: %s", string,
get_system_error_message ());
blog->write (LOG_ERROR, 809, "%s", error_message);
error = true;
}

if (environment)
destroy_environment_block (environment);

if (settings->roll_call.load_user_profile)
unload_user_profile (token, profile_info.hProfile);

CloseHandle (token);
FreeLibrary (module);
}


.



Relevant Pages

  • Re: How to execute a process under another account - PROPERLY?
    ... elsewhere on the network and not accessible from the local system account. ... CreateEnvironmentBlock - to create user's environment ... goto OPEN_DOORS; ... revert_to_self, error_message, error, string)) ...
    (microsoft.public.win32.programmer.kernel)
  • Re: trying to run executable on server
    ... your account has rights to execute it? ... you have an arguments in the string ...
    (microsoft.public.dotnet.framework.aspnet)
  • Re: Execute Persmission denied on object sp_OACreate
    ... > I logged in as that user, tried to execute the DTS ... which then launches the DTS package using the sp_OA* procs? ... account is used during proc execution. ... > proxy account to use in the Job Systems tab of SQL Server Agent ...
    (microsoft.public.sqlserver.security)
  • Execute Process Task not failing, but not executing the batch comm
    ... I can execute the following command from the windows "Run" prompt and it ... Might I have something set weird in SQL Server? ... server being by default configured to run as localsystem account, ...
    (microsoft.public.sqlserver.dts)
  • Re: pass stored procedure parameters in asp
    ... In Management Studio, open a new query window, logging in with the bettys ... account and try to execute the procedure. ... procedure and properties) of voidTran stored procedure and other ...
    (microsoft.public.inetserver.asp.general)