?
Solved

LogonUser trouble

Posted on 2003-03-10
9
Medium Priority
?
732 Views
Last Modified: 2010-04-04
Hi, Im trying to use the function LogonUser, but I keep getting the error "Logon failure: unknown user name or bad password".

Im using LogonUser because I need to create a process running as another user, and CreateProcessAsUser needs a handle, which Im supposed to get from LogonUser. I have a service that starts a .bat file, and this file accesses a network path. This fails because the service runs as system account and cant access network resources. I want to duplicate the behaviour of the Windows Task Scheduler, where you can supply username+password, while the service still runs as system account. How do they do that?

I have of course verified that the username/password's I use are correct ;)

Regards,
Pede
0
Comment
Question by:pede
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 3
9 Comments
 
LVL 6

Accepted Solution

by:
DaFox earned 1000 total points
ID: 8104092
Hi pede.

Example:

procedure WinExecAsUser(FileName: string; username: string; password:
string; Visibility:
  integer);
var { V1 by Pat Ritchey, V2 by P.Below }
  zAppName          : array[0..512] of char;
  StartupInfo       : TStartupInfo;
  ProcessInfo       : TProcessInformation;
  h                 : thandle;
begin { WinExecAndWait32V2 }
  StrPCopy(zAppName, FileName);
  FillChar(StartupInfo, Sizeof(StartupInfo), #0);
  StartupInfo.cb := Sizeof(StartupInfo);
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
  StartupInfo.wShowWindow := Visibility;
  if not LogonUser(pchar(username), '.', pchar(Password),
LOGON32_LOGON_INTERACTIVE,
    LOGON32_PROVIDER_DEFAULT, h) then
    ShowMessage(SysErrorMessage(GetLastError));
  CreateProcessAsUser(h, nil,
    zAppName, { pointer to command line string }
    nil, { pointer to process security attributes }
    nil, { pointer to thread security attributes }
    false, { handle inheritance flag }
    CREATE_NEW_CONSOLE or { creation flags }
    NORMAL_PRIORITY_CLASS,
    nil, { pointer to new environment block }
    nil, { pointer to current directory name }
    StartupInfo, { pointer to STARTUPINFO }
    ProcessInfo); { pointer to PROCESS_INF }
  if GetLastError <> 0 then ShowMessage(SysErrorMessage(GetLastError));
end;

Watch out for your policies (SE_ASSIGNPRIMARYTOKEN_NAME...)!

Markus
0
 
LVL 1

Author Comment

by:pede
ID: 8105921
Hi DaFox, thanks for your comment. Unfortunately Im already doing exactly what you suggested, but I never get past LogonUser, which fails with the error I described above.

It must be some security issue, but I dont know which and why. Im using Win2K server.

The exact scenario is this:

A service creates an out-of-process COM object (starting the COM server, which will terminate when it's done)

The COM object then calls LogonUser because it needs to spawn another process, but not running in the system account context - it must run as a specified user, just at the Task Scheduler does. This call to LogonUser fails. I've tried both with local administrator and the currently logged on user.


0
 
LVL 6

Expert Comment

by:DaFox
ID: 8106626
Hi Pede.

-
const
  SE_CREATE_TOKEN_NAME = 'SeCreateTokenPrivilege';
  SE_ASSIGNPRIMARYTOKEN_NAME = 'SeAssignPrimaryTokenPrivilege';
  SE_LOCK_MEMORY_NAME = 'SeLockMemoryPrivilege';
  SE_INCREASE_QUOTA_NAME = 'SeIncreaseQuotaPrivilege';
  SE_UNSOLICITED_INPUT_NAME = 'SeUnsolicitedInputPrivilege';
  SE_MACHINE_ACCOUNT_NAME = 'SeMachineAccountPrivilege';
  SE_TCB_NAME = 'SeTcbPrivilege';
  SE_SECURITY_NAME = 'SeSecurityPrivilege';
  SE_TAKE_OWNERSHIP_NAME = 'SeTakeOwnershipPrivilege';
  SE_LOAD_DRIVER_NAME = 'SeLoadDriverPrivilege';
  SE_SYSTEM_PROFILE_NAME = 'SeSystemProfilePrivilege';
  SE_SYSTEMTIME_NAME = 'SeSystemtimePrivilege';
  SE_PROF_SINGLE_PROCESS_NAME = 'SeProfileSingleProcessPrivilege';
  SE_INC_BASE_PRIORITY_NAME = 'SeIncreaseBasePriorityPrivilege';
  SE_CREATE_PAGEFILE_NAME = 'SeCreatePagefilePrivilege';
  SE_CREATE_PERMANENT_NAME = 'SeCreatePermanentPrivilege';
  SE_BACKUP_NAME = 'SeBackupPrivilege';
  SE_RESTORE_NAME = 'SeRestorePrivilege';
  SE_SHUTDOWN_NAME = 'SeShutdownPrivilege';
  SE_DEBUG_NAME = 'SeDebugPrivilege';
  SE_AUDIT_NAME = 'SeAuditPrivilege';
  SE_SYSTEM_ENVIRONMENT_NAME = 'SeSystemEnvironmentPrivilege';
  SE_CHANGE_NOTIFY_NAME = 'SeChangeNotifyPrivilege';
  SE_REMOTE_SHUTDOWN_NAME = 'SeRemoteShutdownPrivilege';
  SE_UNDOCK_NAME = 'SeUndockPrivilege';
  SE_SYNC_AGENT_NAME = 'SeSyncAgentPrivilege';
  SE_ENABLE_DELEGATION_NAME = 'SeEnableDelegationPrivilege';

function SetPrivilege(PrivilegeName: String; Enable: Boolean): Boolean;
var
  aTP      : TTokenPrivileges;
  aTPOld   : TTokenPrivileges;
  hToken   : THandle;
  dwRetLen : DWord;
begin
  Result := False;
  OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken);
  aTP.PrivilegeCount := 1;
  if LookupPrivilegeValue(nil, PChar(PrivilegeName), aTP.Privileges[0].LUID) then
  begin
    if Enable then aTP.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED else aTP.Privileges[0].Attributes := 0;
    dwRetLen := 0;
    Result := AdjustTokenPrivileges(hToken, False, aTP, SizeOf(aTPOld), aTPOld, dwRetLen);
  end;
  CloseHandle(hToken);
end;
-

I suppose the privileges you need are: SE_TCB_NAME, SE_ASSIGNPRIMARYTOKEN_NAME, SE_INCREASE_QUOTA_NAME.

Good luck ;-)
Markus
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:pede
ID: 8109854
Well, it looked promising but it didnt help :( SetPrivilege succeeds but I still get the same error on LogonUser. To me it looks like he system account cant detect that the given user accounts exist, and therefore reports them as unknown. Is this possible?
0
 

Expert Comment

by:kbb2
ID: 8110861
Listening... (muhaha)
0
 
LVL 1

Author Comment

by:pede
ID: 8111674
I just tried the function CreateProcessWithLogonW to see if that would work, and I get the exact same error:

Logon failure: unknown user name or bad password

I tried with local administrator and Im 100% sure the password is correct.
0
 
LVL 1

Author Comment

by:pede
ID: 8112095
There's something thats a bit strange about your SetPrivilege function. AdjustTokenPrivileges returns TRUE when I try to set SE_TCB_NAME, but it doesnt get set by the call. If you check the following way you will see that it actually fails:

   AdjustTokenPrivileges(hToken, False, aTP, SizeOf(aTPOld), aTPOld, dwRetLen);
   Result := GetLastError = ERROR_SUCCESS;

It fails with "Not all privileges referenced are assigned to the caller" which means that SE_TCB_NAME is not enabled for the account, and cannot be set.

I have absolutely no control over the accounts that is going to run this - all I have will be domain\username and password. So I guess LogonUser is not an option at all. I wonder how RunAs.exe and Task Scheduler does it.

Thanks for your help, but it looks like Im down the wrong track.

Regards,
Pede


0
 
LVL 1

Author Comment

by:pede
ID: 8113139
Problem solved! I think I now have an understanding of how it all works ;) I cant call LogonUser as any user, because none of the users has the SE_TCB_NAME privilege. That is how its supposed to be, according to the Windows security model.

But - It DOES work when running from inside my service. Believe it or not, but the password was converted to uppercase somewhere along the way (it's a pretty big program and the password travels from disk, through a service and via DCOM to the final .exe that calls LogonUser).

Thank you for your suggestions in this thread :-)
0
 
LVL 6

Expert Comment

by:DaFox
ID: 8114813
I just came home from work and my plan was to work on your prob tonight! Seems like you were a little bit faster... ;-)

Thanks for the points and the explanation!

Markus
0

Featured Post

[Webinar] How Hackers Steal Your Credentials

Do You Know How Hackers Steal Your Credentials? Join us and Skyport Systems to learn how hackers steal your credentials and why Active Directory must be secure to stop them.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
In this video we outline the Physical Segments view of NetCrunch network monitor. By following this brief how-to video, you will be able to learn how NetCrunch visualizes your network, how granular is the information collected, as well as where to f…
Add bar graphs to Access queries using Unicode block characters. Graphs appear on every record in the color you want. Give life to numbers. Hopes this gives you ideas on visualizing your data in new ways ~ Create a calculated field in a query: …
Suggested Courses
Course of the Month9 days, 19 hours left to enroll

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question