Leaked source code of windows server 2003
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.

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