?
Solved

running an application with assumed local admin privileges / Shell Execute question

Posted on 2005-03-25
4
Medium Priority
?
675 Views
Last Modified: 2008-01-09
We have a corp environment and our user are not local administrators on the workstations.  We have a few applications that need to be run w/ local admin privileges so I'm attempting to make a launcher application what will launch another exe as the local administrator account on the workstation.  I Have the impersonation working but when i use CreateProcessAsUser i get an error saying "a required privilege is not held by the client" error.

I need this to work similarly to RunAs on XP :)  Any help is greatly appreciated ;)

here is what I have so far (from various places):
            HANDLE hToken;
            CString sLogin, sPwd, tmp;
            LPVOID lpMsgBuf= NULL;
            LPTSTR lpBuffer;
            lpBuffer = new char[MAX_PATH];
            DWORD dwSize = MAX_PATH + 1;      
            
            STARTUPINFO startup_info;
            PROCESS_INFORMATION process_information;
            
            sLogin = "localadmin"; // valid account
            sPwd = "password";

            GetUserName(lpBuffer, &dwSize); // shows currently logged in user
            cout << "(before) I am currently: " << lpBuffer << endl;
            
            if (!LogonUser((char*)(LPCTSTR)sLogin, NULL, (char*)(LPCTSTR)sPwd,
                  LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken))
            {
                   FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
                         FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                                                 (LPTSTR) &lpMsgBuf,     0,     NULL);
                   tmp.Format("%s %s error logon: %s\n", sPwd, sLogin, lpMsgBuf);
                   cout << tmp << endl;
                   LocalFree(lpMsgBuf);
                   return nRetCode;
            }

            if (!ImpersonateLoggedOnUser(hToken))
            {
                   FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
                         FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                                                 (LPTSTR) &lpMsgBuf,     0,     NULL);
                   tmp.Format("%s %s error impersonate: %s\n", sLogin, sPwd, lpMsgBuf);
                   cout << tmp << endl;
                   LocalFree(lpMsgBuf);
                   return nRetCode;
            }

            GetUserName(lpBuffer, &dwSize); // now shows localadmin
            cout << "(after)  I am currently: " << lpBuffer << endl;

            ZeroMemory(&process_information,sizeof(process_information));
            GetStartupInfo(&startup_info);
            startup_info.cb=sizeof(STARTUPINFO);

            if(!CreateProcessAsUser(hToken, "calc.exe", "",NULL,NULL,FALSE,
                  (DWORD)NULL,NULL,NULL,&startup_info,&process_information))
            {
                   FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
                         FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
                         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                                                 (LPTSTR) &lpMsgBuf,     0,     NULL);
                   tmp.Format("%s %s error CreateProcessAsUser: %s\n", sLogin, sPwd, lpMsgBuf);
                   cout << (LPCTSTR)tmp << endl;
                   LocalFree(lpMsgBuf);
                   return nRetCode;
            }
0
Comment
Question by:jploettner
[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
  • 2
4 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 13632279
The avvount you want to call 'LogonUser()' from needs to hold the the SE_TCB_NAME (aka "SeTcbPrivilege" or "Act as part of the operating system") privilege. You will have to assign that, or it won't work. The docs on 'LogonUser()' mention that explicitly:

"The process that calls LogonUser must have the SE_TCB_NAME privilege. The privilege does not need to be enabled. The LogonUser function enables the privilege as necessary. If the calling process does not have this privilege, LogonUser fails and GetLastError returns ERROR_PRIVILEGE_NOT_HELD.

In some cases, the process that calls LogonUser must also have the SE_CHANGE_NOTIFY_NAME privilege enabled; otherwise, LogonUser fails and GetLastError returns ERROR_ACCESS_DENIED. This privilege is not required for the local system account or accounts that are members of the administrators group. By default, SE_CHANGE_NOTIFY_NAME is enabled for all users, but some administrators may disable it for everyone."
0
 

Author Comment

by:jploettner
ID: 13643239
jkr:

Seems you are the one that usually saves me :)

I tried the SE_TCB_NAME susgestion, here is the error from console:
GetUserName(jploettner)
calling OpenProcessToken...
OpenProcessToken worked...
calling LogonUser...
LogonUser worked...
calling ImpersonateLoggedOnUser...
ImpersonateLoggedOnUser worked...
GetUserName(snowman)
calling CreateProcessAsUser...
==================================
Error Source: CreateProcessAsUser
Error       : A required privilege is not held by the client.
==================================
Press any key to continue

I tried with and with out the ImpersonateLoggedOnUser :(  I'de give you 1000 points for this one if i could, work is torturing me over it and stuck in the mud :P

here is the lastest source:
            CString sLogin, sPwd, tmp;
            LPVOID lpMsgBuf= NULL;
            LPTSTR lpBuffer;
            lpBuffer = new char[MAX_PATH];
            DWORD dwSize = MAX_PATH + 1;      
            
            STARTUPINFO startup_info;
            PROCESS_INFORMATION process_information;
            TOKEN_PRIVILEGES tkp;
            HANDLE hToken;

            sLogin = "snowman"; // local admin account
            sPwd = "mypassword";

            GetUserName(lpBuffer, &dwSize);
            cout << "GetUserName(" << lpBuffer << ")" << endl;

            cout << "calling OpenProcessToken..." << endl;
            if(OpenProcessToken(GetCurrentProcess(),
                  TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
            {
                  if (!LookupPrivilegeValue(NULL, SE_TCB_NAME, &tkp.Privileges[0].Luid))
                  {
                        showerror("LookUpPrivilegeValue");
                        return nRetCode;
                  }

                  tkp.PrivilegeCount = 1;
                  tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
                  if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0))
                  {
                        showerror("AdjustTokenPrivileges");
                        return nRetCode;
                  }

                  cout << "OpenProcessToken worked..." << endl;
            }
            else
            {
                  showerror("OpenProcessToken");
                  return nRetCode;
            }

            cout << "calling LogonUser..." << endl;
            if (!LogonUser((char*)(LPCTSTR)sLogin, NULL, (char*)(LPCTSTR)sPwd,
                  LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken))
            {
                  showerror("LogonUser");
                  return nRetCode;
            }
            else
                  cout << "LogonUser worked..." << endl;

            cout << "calling ImpersonateLoggedOnUser..." << endl;
            if (!ImpersonateLoggedOnUser(hToken))
            {
                  showerror("ImpersonateLoggedOnUser");
                  return nRetCode;
            }
            else
                  cout << "ImpersonateLoggedOnUser worked..." << endl;
            
            GetUserName(lpBuffer, &dwSize);
            cout << "GetUserName(" << lpBuffer << ")" << endl;

            ZeroMemory(&process_information,sizeof(process_information));
            GetStartupInfo(&startup_info);
            startup_info.cb=sizeof(STARTUPINFO);

          char app[] = "calc.exe";
            cout << "calling CreateProcessAsUser..." << endl;
            if (!CreateProcessAsUser(hToken, app, "", NULL, NULL, TRUE, NULL, NULL,
                  "c:\\windows\\system32\\", &startup_info, &process_information))
            {  
                  showerror("CreateProcessAsUser");
                  return nRetCode;
            }
            else
            {
                  cout << "CreateProcessAsUser worked..." << endl;
                  
                  CloseHandle(process_information.hProcess);
                  CloseHandle(process_information.hThread);
            }

0
 
LVL 86

Accepted Solution

by:
jkr earned 2000 total points
ID: 13646018
Hmm, see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createprocessasuser.asp ("CreateProcessAsUser") - this API also requires SE_ASSIGNPRIMARYTOKEN_NAME ("SeAssignPrimaryTokenPrivilege" aka "Replace a process level token") and SE_INCREASE_QUOTA_NAME ("SeIncreaseQuotaPrivilege" aka "Increase quotas").
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

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

In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
Suggested Courses

770 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