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.

781 lines
18 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. wsutil.c
  5. Abstract:
  6. This module contains miscellaneous utility routines used by the
  7. Workstation service.
  8. Author:
  9. Rita Wong (ritaw) 01-Mar-1991
  10. Revision History:
  11. --*/
  12. #include "wsutil.h"
  13. //-------------------------------------------------------------------//
  14. // //
  15. // Local function prototypes //
  16. // //
  17. //-------------------------------------------------------------------//
  18. STATIC
  19. NET_API_STATUS
  20. WsGrowTable(
  21. IN PUSERS_OBJECT Users
  22. );
  23. //-------------------------------------------------------------------//
  24. // //
  25. // Global variables //
  26. // //
  27. //-------------------------------------------------------------------//
  28. //
  29. // Debug trace flag for selecting which trace statements to output
  30. //
  31. #if DBG
  32. DWORD WorkstationTrace = 0;
  33. #endif // DBG
  34. NET_API_STATUS
  35. WsInitializeUsersObject(
  36. IN PUSERS_OBJECT Users
  37. )
  38. /*++
  39. Routine Description:
  40. This function allocates the table of users, and initializes the resource
  41. to serialize access to this table.
  42. Arguments:
  43. Users - Supplies a pointer to the users object.
  44. Return Value:
  45. NET_API_STATUS - NERR_Success or reason for failure.
  46. --*/
  47. {
  48. //
  49. // Allocate the users table memory so that it can be grown (reallocated)
  50. // as more entries are needed.
  51. //
  52. if ((Users->TableMemory = (HANDLE) LocalAlloc(
  53. LMEM_ZEROINIT | LMEM_MOVEABLE,
  54. INITIAL_USER_COUNT * sizeof(PER_USER_ENTRY)
  55. )) == NULL) {
  56. return GetLastError();
  57. }
  58. Users->TableSize = INITIAL_USER_COUNT;
  59. //
  60. // Keep the memory from moving by locking it to a specific location in
  61. // virtual memory. When it is necessary to grow this table, which may
  62. // result in the virtual memory being relocated, it will be unlocked.
  63. //
  64. if ((Users->Table = (PPER_USER_ENTRY)
  65. LocalLock(Users->TableMemory)) == NULL) {
  66. return GetLastError();
  67. }
  68. //
  69. // Initialize the resource for the users table.
  70. //
  71. try {
  72. RtlInitializeResource(&Users->TableResource);
  73. } except(EXCEPTION_EXECUTE_HANDLER) {
  74. return RtlNtStatusToDosError(GetExceptionCode());
  75. }
  76. return NERR_Success;
  77. }
  78. VOID
  79. WsDestroyUsersObject(
  80. IN PUSERS_OBJECT Users
  81. )
  82. /*++
  83. Routine Description:
  84. This function free the table allocated for logged on users, and deletes
  85. the resource used to serialize access to this table.
  86. Arguments:
  87. Users - Supplies a pointer to the users object.
  88. Return Value:
  89. None.
  90. --*/
  91. {
  92. //
  93. // Unlock the memory holding the table to allow us to free it.
  94. //
  95. LocalUnlock(Users->TableMemory);
  96. (void) LocalFree(Users->TableMemory);
  97. RtlDeleteResource(&(Users->TableResource));
  98. }
  99. NET_API_STATUS
  100. WsGetUserEntry(
  101. IN PUSERS_OBJECT Users,
  102. IN PLUID LogonId,
  103. OUT PULONG Index,
  104. IN BOOL IsAdd
  105. )
  106. /*++
  107. Routine Description:
  108. This function searches the table of user entries for one that matches the
  109. specified LogonId, and returns the index to the entry found. If none is
  110. found, an error is returned if IsAdd is FALSE. If IsAdd is TRUE a new
  111. entry in the users table is created for the user and the index to this
  112. new entry is returned.
  113. WARNING: This function assumes that the users table resource has been
  114. claimed.
  115. Arguments:
  116. Users - Supplies a pointer to the users object.
  117. LogonId - Supplies the pointer to the current user's Logon Id.
  118. Index - Returns the index to the users table of entry belonging to the
  119. current user.
  120. IsAdd - Supplies flag to indicate whether to add a new entry for the
  121. current user if none is found.
  122. Return Value:
  123. NET_API_STATUS - NERR_Success or reason for failure.
  124. --*/
  125. {
  126. NET_API_STATUS status;
  127. DWORD i;
  128. ULONG FreeEntryIndex = MAXULONG;
  129. for (i = 0; i < Users->TableSize; i++) {
  130. //
  131. // If the LogonId matches the entry in the UsersTable, we've found the
  132. // correct user entry.
  133. //
  134. if (RtlEqualLuid(LogonId, &Users->Table[i].LogonId)) {
  135. *Index = i;
  136. return NERR_Success;
  137. }
  138. else if (FreeEntryIndex == MAXULONG && Users->Table[i].List == NULL) {
  139. //
  140. // Save away first unused entry in table.
  141. //
  142. FreeEntryIndex = i;
  143. }
  144. }
  145. if (! IsAdd) {
  146. //
  147. // Current user is not found in users table and we are told not to
  148. // create a new entry
  149. //
  150. return NERR_UserNotFound;
  151. }
  152. //
  153. // Could not find an empty entry in the UsersTable, need to grow
  154. //
  155. if (FreeEntryIndex == MAXULONG) {
  156. if ((status = WsGrowTable(Users)) != NERR_Success) {
  157. return status;
  158. }
  159. FreeEntryIndex = i;
  160. }
  161. //
  162. // Create a new entry for current user
  163. //
  164. RtlCopyLuid(&Users->Table[FreeEntryIndex].LogonId, LogonId);
  165. *Index = FreeEntryIndex;
  166. return NERR_Success;
  167. }
  168. STATIC
  169. NET_API_STATUS
  170. WsGrowTable(
  171. IN PUSERS_OBJECT Users
  172. )
  173. /*++
  174. Routine Description:
  175. This function grows the users table to accomodate more users.
  176. WARNING: This function assumes that the users table resource has been
  177. claimed.
  178. Arguments:
  179. Users - Supplies a pointer to the users object.
  180. Return Value:
  181. NET_API_STATUS - NERR_Success or reason for failure.
  182. --*/
  183. {
  184. HANDLE hTemp;
  185. //
  186. // Unlock the Use Table virtual memory so that Win32 can move it
  187. // around to find a larger piece of contiguous virtual memory if
  188. // necessary.
  189. //
  190. LocalUnlock(Users->TableMemory);
  191. //
  192. // Grow users table
  193. //
  194. hTemp = LocalReAlloc(Users->TableMemory,
  195. (Users->TableSize + GROW_USER_COUNT)
  196. * sizeof(PER_USER_ENTRY),
  197. LMEM_ZEROINIT | LMEM_MOVEABLE
  198. );
  199. if (hTemp == NULL) {
  200. return GetLastError();
  201. }
  202. Users->TableMemory = hTemp;
  203. //
  204. // Update new size of Use Table
  205. //
  206. Users->TableSize += GROW_USER_COUNT;
  207. //
  208. // Lock Use Table virtual memory so that it cannot be moved
  209. //
  210. if ((Users->Table = (PPER_USER_ENTRY)
  211. LocalLock(Users->TableMemory)) == NULL) {
  212. return GetLastError();
  213. }
  214. return NERR_Success;
  215. }
  216. NET_API_STATUS
  217. WsMapStatus(
  218. IN NTSTATUS NtStatus
  219. )
  220. /*++
  221. Routine Description:
  222. This function takes an NT status code and maps it to the appropriate
  223. error code expected from calling a LAN Man API.
  224. Arguments:
  225. NtStatus - Supplies the NT status.
  226. Return Value:
  227. Returns the appropriate LAN Man error code for the NT status.
  228. --*/
  229. {
  230. //
  231. // A small optimization for the most common case.
  232. //
  233. if (NtStatus == STATUS_SUCCESS) {
  234. return NERR_Success;
  235. }
  236. switch (NtStatus) {
  237. case STATUS_OBJECT_NAME_COLLISION:
  238. return ERROR_ALREADY_ASSIGNED;
  239. case STATUS_OBJECT_NAME_NOT_FOUND:
  240. return NERR_UseNotFound;
  241. case STATUS_IMAGE_ALREADY_LOADED:
  242. case STATUS_REDIRECTOR_STARTED:
  243. return ERROR_SERVICE_ALREADY_RUNNING;
  244. case STATUS_REDIRECTOR_HAS_OPEN_HANDLES:
  245. return ERROR_REDIRECTOR_HAS_OPEN_HANDLES;
  246. default:
  247. return NetpNtStatusToApiStatus(NtStatus);
  248. }
  249. }
  250. int
  251. WsCompareString(
  252. IN LPTSTR String1,
  253. IN DWORD Length1,
  254. IN LPTSTR String2,
  255. IN DWORD Length2
  256. )
  257. /*++
  258. Routine Description:
  259. This function compares two strings based on their lengths. The return
  260. value indicates if the strings are equal or String1 is less than String2
  261. or String1 is greater than String2.
  262. This function is a modified version of RtlCompareString.
  263. Arguments:
  264. String1 - Supplies the pointer to the first string.
  265. Length1 - Supplies the length of String1 in characters.
  266. String2 - Supplies the pointer to the second string.
  267. Length2 - Supplies the length of String2 in characters.
  268. Return Value:
  269. Signed value that gives the results of the comparison:
  270. 0 - String1 equals String2
  271. < 0 - String1 less than String2
  272. > 0 - String1 greater than String2
  273. --*/
  274. {
  275. TCHAR Char1, Char2;
  276. int CharDiff;
  277. while (Length1 && Length2) {
  278. Char1 = *String1++;
  279. Char2 = *String2++;
  280. if ((CharDiff = (Char1 - Char2)) != 0) {
  281. return CharDiff;
  282. }
  283. Length1--;
  284. Length2--;
  285. }
  286. return Length1 - Length2;
  287. }
  288. int
  289. WsCompareStringU(
  290. IN LPWSTR String1,
  291. IN DWORD Length1,
  292. IN LPTSTR String2,
  293. IN DWORD Length2
  294. )
  295. {
  296. UNICODE_STRING S1;
  297. UNICODE_STRING S2;
  298. int rValue;
  299. S1.Length =
  300. S1.MaximumLength = (USHORT) (Length1 * sizeof(WCHAR));
  301. S1.Buffer = String1;
  302. S2.Length =
  303. S2.MaximumLength = (USHORT) (Length2 * sizeof(WCHAR));
  304. S2.Buffer = String2;
  305. rValue = RtlCompareUnicodeString(&S1, &S2, TRUE);
  306. return(rValue);
  307. }
  308. BOOL
  309. WsCopyStringToBuffer(
  310. IN PUNICODE_STRING SourceString,
  311. IN LPBYTE FixedPortion,
  312. IN OUT LPTSTR *EndOfVariableData,
  313. OUT LPTSTR *DestinationStringPointer
  314. )
  315. /*++
  316. Routine Description:
  317. This function converts the unicode source string to ANSI string (if
  318. we haven't flipped the unicode switch yet) and calls
  319. NetpCopyStringToBuffer.
  320. Arguments:
  321. SourceString - Supplies a pointer to the source string to copy into the
  322. output buffer. If String is null then a pointer to a zero terminator
  323. is inserted into output buffer.
  324. FixedDataEnd - Supplies a pointer to just after the end of the last
  325. fixed structure in the buffer.
  326. EndOfVariableData - Supplies an address to a pointer to just after the
  327. last position in the output buffer that variable data can occupy.
  328. Returns a pointer to the string written in the output buffer.
  329. DestinationStringPointer - Supplies a pointer to the place in the fixed
  330. portion of the output buffer where a pointer to the variable data
  331. should be written.
  332. Return Value:
  333. Returns TRUE if string fits into output buffer, FALSE otherwise.
  334. --*/
  335. {
  336. if (! NetpCopyStringToBuffer(
  337. SourceString->Buffer,
  338. SourceString->Length / sizeof(WCHAR),
  339. FixedPortion,
  340. EndOfVariableData,
  341. DestinationStringPointer
  342. )) {
  343. return FALSE;
  344. }
  345. return TRUE;
  346. }
  347. NET_API_STATUS
  348. WsImpersonateClient(
  349. VOID
  350. )
  351. /*++
  352. Routine Description:
  353. This function calls RpcImpersonateClient to impersonate the current caller
  354. of an API.
  355. Arguments:
  356. None.
  357. Return Value:
  358. NET_API_STATUS - NERR_Success or reason for failure.
  359. --*/
  360. {
  361. NET_API_STATUS status;
  362. if ((status = RpcImpersonateClient(NULL)) != NERR_Success) {
  363. NetpKdPrint(("[Wksta] Fail to impersonate client 0x%x\n", status));
  364. }
  365. return status;
  366. }
  367. NET_API_STATUS
  368. WsRevertToSelf(
  369. VOID
  370. )
  371. /*++
  372. Routine Description:
  373. This function calls RpcRevertToSelf to undo an impersonation.
  374. Arguments:
  375. None.
  376. Return Value:
  377. NET_API_STATUS - NERR_Success or reason for failure.
  378. --*/
  379. {
  380. NET_API_STATUS status;
  381. if (( status = RpcRevertToSelf()) != NERR_Success) {
  382. NetpKdPrint(("[Wksta] Fail to revert to self 0x%x\n", status));
  383. NetpAssert(FALSE);
  384. }
  385. return status;
  386. }
  387. NET_API_STATUS
  388. WsImpersonateAndGetLogonId(
  389. OUT PLUID LogonId
  390. )
  391. /*++
  392. Routine Description:
  393. This function gets the logon id of the current thread.
  394. Arguments:
  395. LogonId - Returns the logon id of the current process.
  396. Return Value:
  397. NET_API_STATUS - NERR_Success or reason for failure.
  398. --*/
  399. {
  400. NET_API_STATUS status;
  401. NTSTATUS ntstatus;
  402. HANDLE CurrentThreadToken;
  403. TOKEN_STATISTICS TokenStats;
  404. ULONG ReturnLength;
  405. if ((status = WsImpersonateClient()) != NERR_Success) {
  406. return status;
  407. }
  408. ntstatus = NtOpenThreadToken(
  409. NtCurrentThread(),
  410. TOKEN_QUERY,
  411. TRUE, // Use workstation service's security
  412. // context to open thread token
  413. &CurrentThreadToken
  414. );
  415. status = NetpNtStatusToApiStatus(ntstatus);
  416. if (! NT_SUCCESS(ntstatus)) {
  417. NetpKdPrint(("[Wksta] Cannot open the current thread token %08lx\n",
  418. ntstatus));
  419. goto RevertToSelf;
  420. }
  421. //
  422. // Get the logon id of the current thread
  423. //
  424. ntstatus = NtQueryInformationToken(
  425. CurrentThreadToken,
  426. TokenStatistics,
  427. (PVOID) &TokenStats,
  428. sizeof(TokenStats),
  429. &ReturnLength
  430. );
  431. status = NetpNtStatusToApiStatus(ntstatus);
  432. if (! NT_SUCCESS(ntstatus)) {
  433. NetpKdPrint(("[Wksta] Cannot query current thread's token %08lx\n",
  434. ntstatus));
  435. NtClose(CurrentThreadToken);
  436. goto RevertToSelf;
  437. }
  438. RtlCopyLuid(LogonId, &TokenStats.AuthenticationId);
  439. NtClose(CurrentThreadToken);
  440. RevertToSelf:
  441. WsRevertToSelf();
  442. return status;
  443. }
  444. NET_API_STATUS
  445. WsOpenDestinationMailslot(
  446. IN LPWSTR TargetName,
  447. IN LPWSTR MailslotName,
  448. OUT PHANDLE MailslotHandle
  449. )
  450. /*++
  451. Routine Description:
  452. This function combines the target domain or computer name and the mailslot
  453. name to form the destination mailslot name. It then opens this destination
  454. mailslot and returns a handle to it.
  455. Arguments:
  456. TargetName - Supplies the name of a domain or computer which we want to
  457. target when sending a mailslot message.
  458. MailslotName - Supplies the name of the mailslot.
  459. MailslotHandle - Returns the handle to the destination mailslot of
  460. \\TargetName\MailslotName.
  461. Return Value:
  462. NET_API_STATUS - NERR_Success or reason for failure.
  463. --*/
  464. {
  465. NET_API_STATUS status = NERR_Success;
  466. LPWSTR DestinationMailslot;
  467. if ((DestinationMailslot = (LPWSTR) LocalAlloc(
  468. LMEM_ZEROINIT,
  469. (UINT) (wcslen(TargetName) +
  470. wcslen(MailslotName) +
  471. 3) * sizeof(WCHAR)
  472. )) == NULL) {
  473. return GetLastError();
  474. }
  475. wcscpy(DestinationMailslot, L"\\\\");
  476. wcscat(DestinationMailslot, TargetName);
  477. wcscat(DestinationMailslot, MailslotName);
  478. if ((*MailslotHandle = (HANDLE) CreateFileW(
  479. DestinationMailslot,
  480. GENERIC_WRITE,
  481. FILE_SHARE_WRITE | FILE_SHARE_READ,
  482. (LPSECURITY_ATTRIBUTES) NULL,
  483. OPEN_EXISTING,
  484. FILE_ATTRIBUTE_NORMAL,
  485. NULL
  486. )) == INVALID_HANDLE_VALUE) {
  487. status = GetLastError();
  488. NetpKdPrint(("[Wksta] Error opening mailslot %s %lu",
  489. DestinationMailslot, status));
  490. }
  491. (void) LocalFree(DestinationMailslot);
  492. return status;
  493. }
  494. NET_API_STATUS
  495. WsImpersonateAndGetSessionId(
  496. OUT PULONG pSessionId
  497. )
  498. /*++
  499. Routine Description:
  500. This function gets the session id of the current thread.
  501. Arguments:
  502. pSessionId - Returns the session id of the current process.
  503. Return Value:
  504. NET_API_STATUS - NERR_Success or reason for failure.
  505. --*/
  506. {
  507. NET_API_STATUS status;
  508. NTSTATUS ntstatus;
  509. HANDLE CurrentThreadToken;
  510. ULONG SessionId;
  511. ULONG ReturnLength;
  512. if ((status = WsImpersonateClient()) != NERR_Success) {
  513. return status;
  514. }
  515. ntstatus = NtOpenThreadToken(
  516. NtCurrentThread(),
  517. TOKEN_QUERY,
  518. TRUE, // Use workstation service's security
  519. // context to open thread token
  520. &CurrentThreadToken
  521. );
  522. status = NetpNtStatusToApiStatus(ntstatus);
  523. if (! NT_SUCCESS(ntstatus)) {
  524. NetpKdPrint(("[Wksta] Cannot open the current thread token %08lx\n",
  525. ntstatus));
  526. goto RevertToSelf;
  527. }
  528. //
  529. // Get the session id of the current thread
  530. //
  531. ntstatus = NtQueryInformationToken(
  532. CurrentThreadToken,
  533. TokenSessionId,
  534. &SessionId,
  535. sizeof(ULONG),
  536. &ReturnLength
  537. );
  538. status = NetpNtStatusToApiStatus(ntstatus);
  539. if (! NT_SUCCESS(ntstatus)) {
  540. NetpKdPrint(("[Wksta] Cannot query current thread's token %08lx\n",
  541. ntstatus));
  542. NtClose(CurrentThreadToken);
  543. goto RevertToSelf;
  544. }
  545. NtClose(CurrentThreadToken);
  546. *pSessionId = SessionId;
  547. RevertToSelf:
  548. WsRevertToSelf();
  549. return status;
  550. }