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.

492 lines
12 KiB

  1. /*************************************************************************
  2. *
  3. * execclt.c
  4. *
  5. * Exec service client.
  6. *
  7. * This allows the starting of a program on any CITRIX WinStation under
  8. * the account of the logged on user, or the SYSTEM account for services.
  9. *
  10. * Copyright Microsoft, 1998
  11. *
  12. * Log:
  13. *
  14. *
  15. *
  16. *************************************************************************/
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <ntlsa.h>
  21. #include <ntmsv1_0.h>
  22. #include <lmsname.h>
  23. #include <windows.h>
  24. #include <stdio.h>
  25. #include <execsrv.h>
  26. #include <winsta.h>
  27. #include <syslib.h>
  28. #pragma warning (error:4312)
  29. #if DBG
  30. ULONG
  31. DbgPrint(
  32. PCH Format,
  33. ...
  34. );
  35. #define DBGPRINT(x) DbgPrint x
  36. #if DBGTRACE
  37. #define TRACE0(x) DbgPrint x
  38. #define TRACE1(x) DbgPrint x
  39. #else
  40. #define TRACE0(x)
  41. #define TRACE1(x)
  42. #endif
  43. #else
  44. #define DBGPRINT(x)
  45. #define TRACE0(x)
  46. #define TRACE1(x)
  47. #endif
  48. //
  49. // Forward references
  50. //
  51. PWCHAR
  52. MarshallStringW(
  53. PWCHAR pSource,
  54. PCHAR pBase,
  55. ULONG MaxSize,
  56. PCHAR *ppPtr,
  57. PULONG pCount
  58. );
  59. VOID
  60. AnsiToUnicode(
  61. WCHAR *,
  62. ULONG,
  63. CHAR *
  64. );
  65. /*****************************************************************************
  66. *
  67. * WinStationCreateProcessA
  68. *
  69. * ANSI version of WinStationCreateProcessW
  70. *
  71. * ENTRY:
  72. * Param1 (input/output)
  73. * Comments
  74. *
  75. * EXIT:
  76. * STATUS_SUCCESS - no error
  77. *
  78. ****************************************************************************/
  79. BOOL
  80. WinStationCreateProcessA(
  81. ULONG LogonId,
  82. BOOL System,
  83. PCHAR lpszImageName,
  84. PCHAR lpszCommandLine,
  85. PSECURITY_ATTRIBUTES psaProcess,
  86. PSECURITY_ATTRIBUTES psaThread,
  87. BOOL fInheritHandles,
  88. DWORD fdwCreate,
  89. LPVOID lpvEnvironment,
  90. LPCSTR lpszCurDir,
  91. LPSTARTUPINFOA pStartInfo,
  92. LPPROCESS_INFORMATION pProcInfo
  93. )
  94. {
  95. ULONG Len;
  96. STARTUPINFOW Info;
  97. BOOL Result = FALSE;
  98. PWCHAR pImage = NULL;
  99. PWCHAR pCmdLine = NULL;
  100. PWCHAR pCurDir = NULL;
  101. PWCHAR pDesk = NULL;
  102. PWCHAR pTitle = NULL;
  103. // Convert the valid ANSI strings to UNICODE
  104. if( lpszImageName ) {
  105. Len = (strlen(lpszImageName)+1)*sizeof(WCHAR);
  106. pImage = LocalAlloc( LMEM_FIXED, Len );
  107. if( pImage == NULL ) goto Cleanup;
  108. AnsiToUnicode( pImage, Len, lpszImageName );
  109. }
  110. if( lpszCommandLine ) {
  111. Len = (strlen(lpszCommandLine)+1)*sizeof(WCHAR);
  112. pCmdLine = LocalAlloc( LMEM_FIXED, Len );
  113. if( pCmdLine == NULL ) goto Cleanup;
  114. AnsiToUnicode( pCmdLine, Len, lpszCommandLine );
  115. }
  116. if( lpszCurDir ) {
  117. Len = (strlen(lpszCurDir)+1)*sizeof(WCHAR);
  118. pCurDir = LocalAlloc( LMEM_FIXED, Len );
  119. if( pCurDir == NULL ) goto Cleanup;
  120. AnsiToUnicode( pCurDir, Len, (CHAR*)lpszCurDir );
  121. }
  122. if( pStartInfo->lpDesktop ) {
  123. Len = (strlen(pStartInfo->lpDesktop)+1)*sizeof(WCHAR);
  124. pDesk = LocalAlloc( LMEM_FIXED, Len );
  125. if( pDesk == NULL ) goto Cleanup;
  126. AnsiToUnicode( pDesk, Len, pStartInfo->lpDesktop );
  127. }
  128. if( pStartInfo->lpTitle ) {
  129. Len = (strlen(pStartInfo->lpTitle)+1)*sizeof(WCHAR);
  130. pTitle = LocalAlloc( LMEM_FIXED, Len );
  131. if( pTitle == NULL ) goto Cleanup;
  132. AnsiToUnicode( pTitle, Len, pStartInfo->lpTitle );
  133. }
  134. Info.cb = sizeof(STARTUPINFOW);
  135. Info.lpReserved = (PWCHAR)pStartInfo->lpReserved;
  136. Info.lpDesktop = pDesk;
  137. Info.lpTitle = pTitle;
  138. Info.dwX = pStartInfo->dwX;
  139. Info.dwY = pStartInfo->dwY;
  140. Info.dwXSize = pStartInfo->dwXSize;
  141. Info.dwYSize = pStartInfo->dwYSize;
  142. Info.dwXCountChars = pStartInfo->dwXCountChars;
  143. Info.dwYCountChars = pStartInfo->dwYCountChars;
  144. Info.dwFillAttribute = pStartInfo->dwFillAttribute;
  145. Info.dwFlags = pStartInfo->dwFlags;
  146. Info.wShowWindow = pStartInfo->wShowWindow;
  147. Info.cbReserved2 = pStartInfo->cbReserved2;
  148. Info.lpReserved2 = pStartInfo->lpReserved2;
  149. Info.hStdInput = pStartInfo->hStdInput;
  150. Info.hStdOutput = pStartInfo->hStdOutput;
  151. Info.hStdError = pStartInfo->hStdError;
  152. Result = WinStationCreateProcessW(
  153. LogonId,
  154. System,
  155. pImage,
  156. pCmdLine,
  157. psaProcess,
  158. psaThread,
  159. fInheritHandles,
  160. fdwCreate,
  161. lpvEnvironment,
  162. pCurDir,
  163. &Info,
  164. pProcInfo
  165. );
  166. Cleanup:
  167. if( pImage ) LocalFree( pImage );
  168. if( pCmdLine ) LocalFree( pCmdLine );
  169. if( pCurDir ) LocalFree( pCurDir );
  170. if( pDesk ) LocalFree( pDesk );
  171. if( pTitle ) LocalFree( pTitle );
  172. return( Result );
  173. }
  174. /*****************************************************************************
  175. *
  176. * WinStationCreateProcessW
  177. *
  178. * Create a process on the given WinStation (LogonId)
  179. *
  180. * ENTRY:
  181. * LogonId (input)
  182. * LogonId of WinStation to create process on
  183. *
  184. * Param1 (input/output)
  185. * Comments
  186. *
  187. * EXIT:
  188. * STATUS_SUCCESS - no error
  189. *
  190. ****************************************************************************/
  191. BOOL
  192. WinStationCreateProcessW(
  193. ULONG LogonId,
  194. BOOL System,
  195. PWCHAR lpszImageName,
  196. PWCHAR lpszCommandLine,
  197. PSECURITY_ATTRIBUTES psaProcess,
  198. PSECURITY_ATTRIBUTES psaThread,
  199. BOOL fInheritHandles,
  200. DWORD fdwCreate,
  201. LPVOID lpvEnvionment,
  202. LPWSTR lpszCurDir,
  203. LPSTARTUPINFOW pStartInfo,
  204. LPPROCESS_INFORMATION pProcInfo
  205. )
  206. {
  207. BOOL Result;
  208. HANDLE hPipe = NULL;
  209. WCHAR szPipeName[MAX_PATH];
  210. PCHAR ptr;
  211. ULONG Count, AmountWrote, AmountRead;
  212. DWORD MyProcId;
  213. PEXECSRV_REQUEST pReq;
  214. EXECSRV_REPLY Rep;
  215. CHAR Buf[EXECSRV_BUFFER_SIZE];
  216. ULONG MaxSize = EXECSRV_BUFFER_SIZE;
  217. if( lpszImageName )
  218. TRACE0(("EXECCLIENT: lpszImageName %ws\n",lpszImageName));
  219. if( lpszCommandLine )
  220. TRACE0(("EXECCLIENT: lpszCommandLine %ws\n",lpszCommandLine));
  221. // Winlogon handles all now. System flag tells it what to do
  222. swprintf(szPipeName, EXECSRV_SYSTEM_PIPE_NAME, LogonId);
  223. hPipe = CreateFileW(
  224. szPipeName,
  225. GENERIC_READ|GENERIC_WRITE,
  226. 0, // File share mode
  227. NULL, // default security
  228. OPEN_EXISTING,
  229. 0, // Attrs and flags
  230. NULL // template file handle
  231. );
  232. if( hPipe == INVALID_HANDLE_VALUE ) {
  233. DBGPRINT(("EXECCLIENT: Could not create pipe name %ws\n", szPipeName));
  234. return(FALSE);
  235. }
  236. /*
  237. * Get the handle to the current process
  238. */
  239. MyProcId = GetCurrentProcessId();
  240. /*
  241. * setup the marshalling
  242. */
  243. ptr = Buf;
  244. Count = 0;
  245. pReq = (PEXECSRV_REQUEST)ptr;
  246. ptr += sizeof(EXECSRV_REQUEST);
  247. Count += sizeof(EXECSRV_REQUEST);
  248. // set the basic parameters
  249. pReq->System = System;
  250. pReq->RequestingProcessId = MyProcId;
  251. pReq->fInheritHandles = fInheritHandles;
  252. pReq->fdwCreate = fdwCreate;
  253. // marshall the ImageName string
  254. if( lpszImageName ) {
  255. pReq->lpszImageName = MarshallStringW( lpszImageName, Buf, MaxSize, &ptr, &Count );
  256. }
  257. else {
  258. pReq->lpszImageName = NULL;
  259. }
  260. // marshall in the CommandLine string
  261. if( lpszCommandLine ) {
  262. pReq->lpszCommandLine = MarshallStringW( lpszCommandLine, Buf, MaxSize, &ptr, &Count );
  263. }
  264. else {
  265. pReq->lpszCommandLine = NULL;
  266. }
  267. // marshall in the CurDir string
  268. if( lpszCurDir ) {
  269. pReq->lpszCurDir = MarshallStringW( lpszCurDir, Buf, MaxSize, &ptr, &Count );
  270. }
  271. else {
  272. pReq->lpszCurDir = NULL;
  273. }
  274. // marshall in the StartupInfo structure
  275. RtlMoveMemory( &pReq->StartInfo, pStartInfo, sizeof(STARTUPINFO) );
  276. // Now marshall the strings in STARTUPINFO
  277. if( pStartInfo->lpDesktop ) {
  278. pReq->StartInfo.lpDesktop = MarshallStringW( pStartInfo->lpDesktop, Buf, MaxSize, &ptr, &Count );
  279. }
  280. else {
  281. pReq->StartInfo.lpDesktop = NULL;
  282. }
  283. if( pStartInfo->lpTitle ) {
  284. pReq->StartInfo.lpTitle = MarshallStringW( pStartInfo->lpTitle, Buf, MaxSize, &ptr, &Count );
  285. }
  286. else {
  287. pReq->StartInfo.lpTitle = NULL;
  288. }
  289. //
  290. // WARNING: This version does not pass the following:
  291. //
  292. // Also saProcess and saThread are ignored right now and use
  293. // the users default security on the remote WinStation
  294. //
  295. // Set things that are always NULL
  296. //
  297. pReq->StartInfo.lpReserved = NULL; // always NULL
  298. pReq->lpvEnvironment = NULL;
  299. pReq->hToken = NULL;
  300. // now fill in the total count
  301. pReq->Size = Count;
  302. /*
  303. * Now send the buffer out to the server
  304. */
  305. Result = WriteFile(
  306. hPipe,
  307. Buf,
  308. Count,
  309. &AmountWrote,
  310. NULL
  311. );
  312. if( !Result ) {
  313. DBGPRINT(("EXECCLIENT: Error %d sending request\n",GetLastError()));
  314. goto Cleanup;
  315. }
  316. /*
  317. * Now read the reply
  318. */
  319. Result = ReadFile(
  320. hPipe,
  321. &Rep,
  322. sizeof(Rep),
  323. &AmountRead,
  324. NULL
  325. );
  326. if( !Result ) {
  327. DBGPRINT(("EXECCLIENT: Error %d reading reply\n",GetLastError()));
  328. goto Cleanup;
  329. }
  330. /*
  331. * Check the result
  332. */
  333. if( !Rep.Result ) {
  334. DBGPRINT(("EXECCLIENT: Error %d in reply\n",Rep.LastError));
  335. // set the error in the current thread to the returned error
  336. Result = Rep.Result;
  337. SetLastError( Rep.LastError );
  338. goto Cleanup;
  339. }
  340. /*
  341. * We copy the PROCESS_INFO structure from the reply
  342. * to the caller.
  343. *
  344. * The remote site has duplicated the handles into our
  345. * process space for hProcess and hThread so that they will
  346. * behave like CreateProcessW()
  347. */
  348. RtlMoveMemory( pProcInfo, &Rep.ProcInfo, sizeof( PROCESS_INFORMATION ) );
  349. Cleanup:
  350. CloseHandle(hPipe);
  351. DBGPRINT(("EXECCLIENT: Result 0x%x\n", Result));
  352. return(Result);
  353. }
  354. /*****************************************************************************
  355. *
  356. * MarshallStringW
  357. *
  358. * Marshall in a UNICODE_NULL terminated WCHAR string
  359. *
  360. * ENTRY:
  361. * pSource (input)
  362. * Pointer to source string
  363. *
  364. * pBase (input)
  365. * Base buffer pointer for normalizing the string pointer
  366. *
  367. * MaxSize (input)
  368. * Maximum buffer size available
  369. *
  370. * ppPtr (input/output)
  371. * Pointer to the current context pointer in the marshall buffer.
  372. * This is updated as data is marshalled into the buffer
  373. *
  374. * pCount (input/output)
  375. * Current count of data in the marshall buffer.
  376. * This is updated as data is marshalled into the buffer
  377. *
  378. * EXIT:
  379. * NULL - Error
  380. * !=NULL "normalized" pointer to the string in reference to pBase
  381. *
  382. ****************************************************************************/
  383. PWCHAR
  384. MarshallStringW(
  385. PWCHAR pSource,
  386. PCHAR pBase,
  387. ULONG MaxSize,
  388. PCHAR *ppPtr,
  389. PULONG pCount
  390. )
  391. {
  392. ULONG Len;
  393. PCHAR ptr;
  394. Len = wcslen( pSource );
  395. Len++; // include the NULL;
  396. Len *= sizeof(WCHAR); // convert to bytes
  397. if( (*pCount + Len) > MaxSize ) {
  398. return( NULL );
  399. }
  400. RtlMoveMemory( *ppPtr, pSource, Len );
  401. // the normalized ptr is the current count
  402. ptr = LongToPtr(*pCount);
  403. *ppPtr += Len;
  404. *pCount += Len;
  405. return((PWCHAR)ptr);
  406. }
  407. /*******************************************************************************
  408. *
  409. * AnsiToUnicode
  410. *
  411. * convert an ANSI (CHAR) string into a UNICODE (WCHAR) string
  412. *
  413. * ENTRY:
  414. *
  415. * pUnicodeString (output)
  416. * buffer to place UNICODE string into
  417. * lUnicodeMax (input)
  418. * maximum number of characters to write into pUnicodeString
  419. * pAnsiString (input)
  420. * ANSI string to convert
  421. *
  422. * EXIT:
  423. * nothing (VOID)
  424. *
  425. ******************************************************************************/
  426. VOID
  427. AnsiToUnicode( WCHAR * pUnicodeString,
  428. ULONG lUnicodeMax,
  429. CHAR * pAnsiString )
  430. {
  431. ULONG ByteCount;
  432. RtlMultiByteToUnicodeN( pUnicodeString, lUnicodeMax, &ByteCount,
  433. pAnsiString, (strlen(pAnsiString) + 1) );
  434. }