Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
8.7 KiB

  1. /*************************************************************************
  2. *
  3. * execclt.c
  4. *
  5. * Exec service client.
  6. *
  7. * This allows the starting of a program on any Terminal Server Session under
  8. * the account of the logged on user, or the SYSTEM account for services.
  9. *
  10. * copyright notice: Copyright 1998, Microsoft Corporation
  11. *
  12. *
  13. *
  14. *************************************************************************/
  15. #include "act.hxx"
  16. extern "C" {
  17. #include <execsrv.h>
  18. }
  19. //
  20. // Forward references
  21. //
  22. PWCHAR
  23. MarshallString(
  24. PWCHAR pSource,
  25. PCHAR pBase,
  26. ULONG MaxSize,
  27. PCHAR *ppPtr,
  28. PULONG pCount,
  29. BOOL bMulti = FALSE
  30. );
  31. /*****************************************************************************
  32. *
  33. * CreateRemoteSessionProcess
  34. *
  35. * Create a process on the given Terminal Server Session
  36. *
  37. * ENTRY:
  38. * SessionId (input)
  39. * SessionId of Session to create process on
  40. *
  41. * Param1 (input/output)
  42. * Comments
  43. *
  44. * EXIT:
  45. * STATUS_SUCCESS - no error
  46. *
  47. ****************************************************************************/
  48. BOOL
  49. CreateRemoteSessionProcess(
  50. ULONG SessionId,
  51. HANDLE hSaferToken,
  52. BOOL System,
  53. PWCHAR lpszImageName,
  54. PWCHAR lpszCommandLine,
  55. PSECURITY_ATTRIBUTES psaProcess,
  56. PSECURITY_ATTRIBUTES psaThread,
  57. BOOL fInheritHandles,
  58. DWORD fdwCreate,
  59. LPVOID lpvEnvironment,
  60. LPWSTR lpszCurDir,
  61. LPSTARTUPINFOW pStartInfo,
  62. LPPROCESS_INFORMATION pProcInfo
  63. )
  64. {
  65. BOOL Result;
  66. HANDLE hPipe = NULL;
  67. WCHAR szPipeName[MAX_PATH];
  68. PCHAR ptr;
  69. ULONG Count, AmountWrote, AmountRead;
  70. DWORD MyProcId;
  71. PEXECSRV_REQUEST pReq;
  72. EXECSRV_REPLY Rep;
  73. CHAR Buf[EXECSRV_BUFFER_SIZE];
  74. ULONG MaxSize = EXECSRV_BUFFER_SIZE;
  75. if( lpszImageName )
  76. CairoleDebugOut((DEB_TRACE, "EXECCLIENT: lpszImageName %ws\n",lpszImageName));
  77. if( lpszCommandLine )
  78. CairoleDebugOut((DEB_TRACE, "EXECCLIENT: lpszCommandLine %ws\n",lpszCommandLine));
  79. // Winlogon handles all now. System flag tells it what to do
  80. swprintf(szPipeName, EXECSRV_SYSTEM_PIPE_NAME, SessionId);
  81. while (TRUE) {
  82. hPipe = CreateFileW(
  83. szPipeName,
  84. GENERIC_READ|GENERIC_WRITE,
  85. 0, // File share mode
  86. NULL, // default security
  87. OPEN_EXISTING,
  88. 0, // Attrs and flags
  89. NULL // template file handle
  90. );
  91. if( hPipe == INVALID_HANDLE_VALUE ) {
  92. if (GetLastError() == ERROR_PIPE_BUSY) {
  93. if (!WaitNamedPipe( szPipeName, 30000 )) { // 30 sec
  94. CairoleDebugOut((DEB_ERROR, "EXECCLIENT: Waited too long for pipe name %ws\n", szPipeName));
  95. return(FALSE);
  96. }
  97. } else {
  98. CairoleDebugOut((DEB_ERROR, "EXECCLIENT: Could not create pipe name %ws\n", szPipeName));
  99. return(FALSE);
  100. }
  101. } else {
  102. break;
  103. }
  104. }
  105. /*
  106. * Get the handle to the current process
  107. */
  108. MyProcId = GetCurrentProcessId();
  109. /*
  110. * setup the marshalling
  111. */
  112. ptr = Buf;
  113. Count = 0;
  114. pReq = (PEXECSRV_REQUEST)ptr;
  115. ptr += sizeof(EXECSRV_REQUEST);
  116. Count += sizeof(EXECSRV_REQUEST);
  117. // set the basic parameters
  118. pReq->hToken = hSaferToken;
  119. pReq->System = System;
  120. pReq->RequestingProcessId = MyProcId;
  121. pReq->fInheritHandles = fInheritHandles;
  122. pReq->fdwCreate = fdwCreate;
  123. // marshall the ImageName string
  124. if( lpszImageName ) {
  125. pReq->lpszImageName = MarshallString( lpszImageName, Buf, MaxSize, &ptr, &Count );
  126. }
  127. else {
  128. pReq->lpszImageName = NULL;
  129. }
  130. // marshall in the CommandLine string
  131. if( lpszCommandLine ) {
  132. pReq->lpszCommandLine = MarshallString( lpszCommandLine, Buf, MaxSize, &ptr, &Count );
  133. }
  134. else {
  135. pReq->lpszCommandLine = NULL;
  136. }
  137. // marshall in the CurDir string
  138. if( lpszCurDir ) {
  139. pReq->lpszCurDir = MarshallString( lpszCurDir, Buf, MaxSize, &ptr, &Count );
  140. }
  141. else {
  142. pReq->lpszCurDir = NULL;
  143. }
  144. // marshall in the StartupInfo structure
  145. RtlMoveMemory( &pReq->StartInfo, pStartInfo, sizeof(STARTUPINFO) );
  146. // Now marshall the strings in STARTUPINFO
  147. if( pStartInfo->lpDesktop ) {
  148. pReq->StartInfo.lpDesktop = MarshallString( pStartInfo->lpDesktop, Buf, MaxSize, &ptr, &Count );
  149. }
  150. else {
  151. pReq->StartInfo.lpDesktop = NULL;
  152. }
  153. if( pStartInfo->lpTitle ) {
  154. pReq->StartInfo.lpTitle = MarshallString( pStartInfo->lpTitle, Buf, MaxSize, &ptr, &Count );
  155. }
  156. else {
  157. pReq->StartInfo.lpTitle = NULL;
  158. }
  159. if( lpvEnvironment ) {
  160. pReq->lpvEnvironment = MarshallString( (PWCHAR)lpvEnvironment, Buf, MaxSize, &ptr, &Count, TRUE );
  161. }
  162. else {
  163. pReq->lpvEnvironment = NULL;
  164. }
  165. //
  166. // WARNING: This version does not pass the following:
  167. //
  168. // Also saProcess and saThread are ignored right now and use
  169. // the users default security on the remote WinStation
  170. //
  171. // Set things that are always NULL
  172. //
  173. pReq->StartInfo.lpReserved = NULL; // always NULL
  174. // now fill in the total count
  175. pReq->Size = Count;
  176. /*
  177. * Now send the buffer out to the server
  178. */
  179. Result = WriteFile(
  180. hPipe,
  181. Buf,
  182. Count,
  183. &AmountWrote,
  184. NULL
  185. );
  186. if( !Result ) {
  187. CairoleDebugOut((DEB_ERROR, "EXECCLIENT: Error %d sending request\n",GetLastError()));
  188. goto Cleanup;
  189. }
  190. /*
  191. * Now read the reply
  192. */
  193. Result = ReadFile(
  194. hPipe,
  195. &Rep,
  196. sizeof(Rep),
  197. &AmountRead,
  198. NULL
  199. );
  200. if( !Result ) {
  201. CairoleDebugOut((DEB_ERROR, "EXECCLIENT: Error %d reading reply\n",GetLastError()));
  202. goto Cleanup;
  203. }
  204. /*
  205. * Check the result
  206. */
  207. if( !Rep.Result ) {
  208. CairoleDebugOut((DEB_ERROR, "EXECCLIENT: Error %d in reply\n",Rep.LastError));
  209. // set the error in the current thread to the returned error
  210. Result = Rep.Result;
  211. SetLastError( Rep.LastError );
  212. goto Cleanup;
  213. }
  214. /*
  215. * We copy the PROCESS_INFO structure from the reply
  216. * to the caller.
  217. *
  218. * The remote site has duplicated the handles into our
  219. * process space for hProcess and hThread so that they will
  220. * behave like CreateProcessW()
  221. */
  222. RtlMoveMemory( pProcInfo, &Rep.ProcInfo, sizeof( PROCESS_INFORMATION ) );
  223. Cleanup:
  224. CloseHandle(hPipe);
  225. CairoleDebugOut((DEB_TRACE, "EXECCLIENT: Result 0x%x\n", Result));
  226. return(Result);
  227. }
  228. /*****************************************************************************
  229. *
  230. * MarshallString
  231. *
  232. * Marshall in a UNICODE_NULL terminated WCHAR string
  233. *
  234. * ENTRY:
  235. * pSource (input)
  236. * Pointer to source string
  237. *
  238. * pBase (input)
  239. * Base buffer pointer for normalizing the string pointer
  240. *
  241. * MaxSize (input)
  242. * Maximum buffer size available
  243. *
  244. * ppPtr (input/output)
  245. * Pointer to the current context pointer in the marshall buffer.
  246. * This is updated as data is marshalled into the buffer
  247. *
  248. * pCount (input/output)
  249. * Current count of data in the marshall buffer.
  250. * This is updated as data is marshalled into the buffer
  251. *
  252. * bMulti (optional input)
  253. * If TRUE then marshall in a multi UNICODE string. Each string are
  254. * UNICODE_NULL terminated and the multi string is terminated with a double
  255. * UNICODE_NULL. The default value is FALSE.
  256. *
  257. * EXIT:
  258. * NULL - Error
  259. * !=NULL "normalized" pointer to the string in reference to pBase
  260. *
  261. ****************************************************************************/
  262. PWCHAR
  263. MarshallString(
  264. PWCHAR pSource,
  265. PCHAR pBase,
  266. ULONG MaxSize,
  267. PCHAR *ppPtr,
  268. PULONG pCount,
  269. BOOL bMulti
  270. )
  271. {
  272. ULONG Len;
  273. PCHAR ptr;
  274. if (bMulti) {
  275. Len = 0;
  276. for (PWCHAR pStr = pSource; *pStr; ) {
  277. ULONG StrLen = wcslen( pStr ) + 1; // include the NULL
  278. Len += StrLen;
  279. pStr += StrLen;
  280. // bail out if too long
  281. if( (*pCount + (Len * sizeof(WCHAR))) > MaxSize ) {
  282. return( NULL );
  283. }
  284. }
  285. Len++; // include last NULL
  286. } else {
  287. Len = wcslen( pSource );
  288. Len++; // include the NULL
  289. }
  290. Len *= sizeof(WCHAR); // convert to bytes
  291. if( (*pCount + Len) > MaxSize ) {
  292. return( NULL );
  293. }
  294. RtlMoveMemory( *ppPtr, pSource, Len );
  295. // the normalized ptr is the current count - Sundown: zero-extended value.
  296. ptr = (PCHAR)ULongToPtr(*pCount);
  297. *ppPtr += Len;
  298. *pCount += Len;
  299. return((PWCHAR)ptr);
  300. }