locked
createProcessAsUser gets “access is denied” executing "cmd /c net view \\xxx" in a service RRS feed

  • Question

  • Hi,

    I'm writing a service application that need to list all share folders under remote server . the administrator's username&password will be sent to service, as service is running in localSystem account, so I need to user username& password to impersonate a user.

    The code can work on windows xp, windows server 2008 r2, while on some win7&win8.1 environment, my code get access denied error . And I've tried to write the command string in a batch file which got me the error result as following :

    test.cmd's content :

    "chcp 437
    cmd /c net view <remote server location>

    "

    the way I execute the command is : createProcessAsUser + "cmd /k test.cmd";

    "

    C:\Program Files (x86)\ActiveImage Protector Desktop>chcp 437 

    Active code page: 437

    C:\Program Files (x86)\ActiveImage Protector Desktop>cmd /c net view <remote server location>

    System error 5 has occurred.

    Access is denied.

    "

    code to list the share folders, both executing command string and batch file are as follows, if you want to run the code, just replace CUtf8String with string and use ansi version APIs.

    It's really appreciated for your help and advice

     :

    //================== code for creating token

    HANDLE SpawnLoginLocalPC( const CUtf8String& username,
           const CUtf8String& password){
     //==== log on as user
     HANDLE hLocalUserToken=NULL;

     CUtf8String domain(".");
     CUtf8String UserName( username );

     if(UserName.find('\\') != CUtf8String::npos)
     {
      domain   =  CUtf8String(UserName.substr(0,UserName.find('\\')));
      UserName =  CUtf8String(UserName.substr(UserName.find('\\')+1));
     }
     CAipLogImpl::Inst().WriteLog(LOG_ERROR, "[%s] username(%s) password(%s) domain(%s) ",__FUNCTION__, UserName.c_str(), password.c_str(), domain.c_str()  );

     if( !LogonUserW(UserName.ToWide().c_str(), domain.ToWide().c_str(), password.ToWide().c_str(), LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,&hLocalUserToken) )
     {

      ErrorPrint("LogonUserW");
      return NULL;
     }

     return hLocalUserToken;

    }


    //===== execute command string by token
    void SpawnExecCmd(     HANDLE hLocalUserToken,
             const CUtf8String& strCmd,
             const string& strCmdCompleteIdentifier,
             string& cmdResultStr){

     if(!hLocalUserToken)
     {
      CAipLogImpl::Inst().WriteLog(LOG_ERROR, "[%s] User token not created", __FUNCTION__ );
      return;
     }
     cmdResultStr.clear();

     //==== create pipes ,new process using logon token
     SECURITY_ATTRIBUTES saAttr;
     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
     saAttr.bInheritHandle = TRUE;
     saAttr.lpSecurityDescriptor = NULL;

     HANDLE g_hChildStd_IN_Rd = NULL;
     HANDLE g_hChildStd_IN_Wr = NULL;
     HANDLE g_hChildStd_OUT_Rd = NULL;
     HANDLE g_hChildStd_OUT_Wr = NULL;

     // Create a pipe for the child process's STDOUT.
     if ( ! CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) ) {
      CAipLogImpl::Inst().WriteLog(LOG_ERROR, "Failed to StdoutRd CreatePipe" );  
     }

     // Ensure the read handle to the pipe for STDOUT is not inherited.
     if ( ! SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) ){
      CAipLogImpl::Inst().WriteLog(LOG_ERROR, "Failed to StdoutRd SetHandleInformation" );  
     }

     // Create a pipe for the child process's STDIN.
     if (! CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) {
      CAipLogImpl::Inst().WriteLog(LOG_ERROR, "Failed to Stdin CreatePipe" );  
     }

     // Ensure the write handle to the pipe for STDIN is not inherited.
     if ( ! SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) ){
      CAipLogImpl::Inst().WriteLog(LOG_ERROR, "Failed to Stdin SetHandleInformation" );  
     }
      
     PROCESS_INFORMATION pi;
     BOOL bSpawnOK = FALSE;
     {
      WCHAR desktop[]=L"winsta0\\default";
      STARTUPINFOW si;
      memset(&si, 0, sizeof(si));
      si.cb = sizeof(si);
      //si.wShowWindow = SW_SHOWNORMAL;
      si.wShowWindow = SW_HIDE;
      si.hStdOutput = g_hChildStd_OUT_Wr;
      si.hStdInput  = g_hChildStd_IN_Rd;
      si.hStdError  = g_hChildStd_OUT_Wr;
      si.dwFlags |= STARTF_USESTDHANDLES;

      if( !ImpersonateLoggedOnUser(hLocalUserToken) ){
       CAipLogImpl::Inst().WriteLog(LOG_ERROR, "ImpersonateLoggedOnUser failed" );
      }

      bSpawnOK = CreateProcessAsUserW(hLocalUserToken,
       NULL,
       (LPWSTR)strCmd.ToWide().c_str(),
       NULL,
       NULL,
       TRUE,
       0,
       NULL,NULL,
       &si,
       &pi);
      if( !RevertToSelf() ){
       CAipLogImpl::Inst().WriteLog(LOG_ERROR, "RevertToSelf failed" );
      }

      //CloseHandle(hLocalUserToken); //don't close handle to reuse it later, creating handle is time-consuming,
      CAipLogImpl::Inst().WriteLog(LOG_ERROR, "[%s] CreateProcessAsUserW [%s] result [%s]", __FUNCTION__, strCmd.c_str(), bSpawnOK?"success":"failed");
      if(!bSpawnOK){
       CloseHandle(pi.hProcess);
       CloseHandle(pi.hThread);
       return;
      }

     }

     //===== read output
      
     if ( ! CloseHandle(g_hChildStd_IN_Wr) ){
      CAipLogImpl::Inst().WriteLog(LOG_ERROR, "Failed to CloseHandle g_hChildStd_IN_Wr" );
     }

     DWORD dwRead =0 ;
     const int BUFSIZE = 4096;
     CHAR chBuf[BUFSIZE] = {0};

     const int MAXTRY = 200;
     int tries=0;

     //=== to test this, you can run the command in aip.log manually and check the result, the final content will contain servername
     while ( ( tries++ < MAXTRY ) && ( cmdResultStr.find( strCmdCompleteIdentifier )== CUtf8String::npos ) )
     {
      PeekNamedPipe(g_hChildStd_OUT_Rd, chBuf, sizeof(chBuf), &dwRead,NULL,NULL);

      if(dwRead){
       BOOL bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, sizeof(chBuf), &dwRead, NULL);
       if( ! bSuccess || dwRead == 0 ) break;

       
       cmdResultStr += chBuf;
       chBuf[0] = 0;
      }

      Sleep(100);
     }

     CAipLogImpl::Inst().WriteLog(LOG_ERROR, "cmd output cmdResultStr[%s]",  cmdResultStr.c_str() );

     CloseHandle(pi.hProcess);
     CloseHandle(pi.hThread);

    }

     //==================== code for executing cmd
     HANDLE hLocalUserToken = SpawnLoginLocalPC(  username, password)
     CUtf8String cmd= CUtf8String("cmd.exe chcp 437 & cmd /c net view ") + serverNameOrIP + CUtf8String(" | findstr /C:\"Disk\" ") ;
     string strCmdCompleteIdentifier = "Disk";
     string cmdResultStr;
     SpawnExecCmd(m_hLocalUserToken, cmd, strCmdCompleteIdentifier, cmdResultStr );


    • Edited by rex-zhang Friday, May 16, 2014 11:50 AM
    Friday, May 16, 2014 11:49 AM

All replies

  • I'm sorry I don't have any points, but can anybody have a look at this and give me a reply? It's really appreciated.
    Monday, May 19, 2014 1:00 AM
  • yes , I know that service is running in localSystem account, so I send username&password to service in which I use LogonUser and createProcessAsUser to create a new process with local user account to do network query job, and the problem is it failed with "System Error 5 : access is denied". Do you have any idea?
    Tuesday, May 20, 2014 7:20 AM