main.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. * Copyright 2020 Brendan Shanks for CodeWeavers
  3. * Copyright 2023 Maxim Karasev <mxkrsv@etersoft.ru>
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2.1 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  18. */
  19. #define WIN32_LEAN_AND_MEAN
  20. #define SECURITY_WIN32
  21. #include <windows.h>
  22. #include <security.h>
  23. #include <sddl.h>
  24. #include <stdarg.h>
  25. #include "wine/debug.h"
  26. WINE_DEFAULT_DEBUG_CHANNEL(whoami);
  27. static int output_write(const WCHAR* str, int len)
  28. {
  29. DWORD count;
  30. if (len < 0)
  31. len = wcslen(str);
  32. if (!WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, len, &count, NULL))
  33. {
  34. DWORD lenA;
  35. char *strA;
  36. /* On Windows WriteConsoleW() fails if the output is redirected. So fall
  37. * back to WriteFile() with OEM code page.
  38. */
  39. lenA = WideCharToMultiByte(GetOEMCP(), 0, str, len, NULL, 0, NULL, NULL);
  40. strA = malloc(lenA);
  41. if (!strA)
  42. return 0;
  43. WideCharToMultiByte(GetOEMCP(), 0, str, len, strA, lenA, NULL, NULL);
  44. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), strA, lenA, &count, FALSE);
  45. free(strA);
  46. }
  47. return count;
  48. }
  49. static WCHAR *get_user_name(EXTENDED_NAME_FORMAT name_format)
  50. {
  51. ULONG size = 0;
  52. WCHAR *ret;
  53. if (GetUserNameExW(name_format, NULL, &size) || GetLastError() != ERROR_MORE_DATA)
  54. return NULL;
  55. ret = malloc(size * sizeof(WCHAR));
  56. if (!ret)
  57. return NULL;
  58. if (!GetUserNameExW(name_format, ret, &size))
  59. {
  60. free(ret);
  61. return NULL;
  62. }
  63. return ret;
  64. }
  65. static void *get_token(TOKEN_INFORMATION_CLASS token_type)
  66. {
  67. HANDLE token_handle;
  68. void *ret;
  69. /* GetTokenInformation wants a dword-aligned buffer */
  70. ULONG ret_size = sizeof(DWORD) * 256;
  71. ULONG token_size;
  72. ret = malloc(ret_size);
  73. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token_handle))
  74. return NULL;
  75. if (!GetTokenInformation(token_handle, token_type, ret, ret_size, &token_size))
  76. {
  77. CloseHandle(token_handle);
  78. return NULL;
  79. }
  80. CloseHandle(token_handle);
  81. return ret;
  82. }
  83. static SID *get_process_sid(void)
  84. {
  85. ULONG user_sid_len;
  86. TOKEN_USER *token_user;
  87. SID *ret;
  88. token_user = get_token(TokenUser);
  89. if (!token_user)
  90. return NULL;
  91. user_sid_len = GetLengthSid(token_user->User.Sid);
  92. ret = malloc(user_sid_len);
  93. if (!ret)
  94. {
  95. free(token_user);
  96. return NULL;
  97. }
  98. if (!CopySid(user_sid_len, ret, token_user->User.Sid))
  99. {
  100. free(token_user);
  101. free(ret);
  102. return NULL;
  103. }
  104. free(token_user);
  105. return ret;
  106. }
  107. static SID *get_logon_sid(void)
  108. {
  109. TOKEN_GROUPS *token_groups;
  110. DWORD group_token_len;
  111. DWORD i;
  112. SID *ret;
  113. token_groups = get_token(TokenGroups);
  114. if (!token_groups)
  115. return NULL;
  116. for (i = 0; i < token_groups->GroupCount; i++)
  117. {
  118. if ((token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
  119. {
  120. group_token_len = GetLengthSid(token_groups->Groups[i].Sid);
  121. ret = malloc(group_token_len);
  122. if (!ret)
  123. {
  124. free(token_groups);
  125. return NULL;
  126. }
  127. if (!CopySid(group_token_len, ret, token_groups->Groups[i].Sid))
  128. {
  129. free(token_groups);
  130. free(ret);
  131. return NULL;
  132. }
  133. free(token_groups);
  134. return ret;
  135. }
  136. }
  137. free(token_groups);
  138. return NULL;
  139. }
  140. static int simple(EXTENDED_NAME_FORMAT name_format)
  141. {
  142. WCHAR *name;
  143. name = get_user_name(name_format);
  144. if (!name)
  145. {
  146. ERR("get_user_name failed\n");
  147. return 1;
  148. }
  149. output_write(name, -1);
  150. output_write(L"\n", 1);
  151. free(name);
  152. return 0;
  153. }
  154. static int logon_id(void)
  155. {
  156. PSID sid;
  157. WCHAR *sid_string;
  158. sid = get_logon_sid();
  159. if (!sid)
  160. {
  161. ERR("get_logon_sid failed\n");
  162. return 1;
  163. }
  164. if (!ConvertSidToStringSidW(sid, &sid_string))
  165. {
  166. ERR("ConvertSidToStringSidW failed, error %ld\n", GetLastError());
  167. return 1;
  168. }
  169. output_write(sid_string, -1);
  170. output_write(L"\n", 1);
  171. free(sid);
  172. LocalFree(sid_string);
  173. return 0;
  174. }
  175. static int user(void)
  176. {
  177. PSID sid;
  178. WCHAR *name;
  179. WCHAR *sid_string;
  180. ULONG i;
  181. name = get_user_name(NameSamCompatible);
  182. if (!name)
  183. {
  184. ERR("get_user_name failed\n");
  185. return 1;
  186. }
  187. sid = get_process_sid();
  188. if (!sid)
  189. {
  190. ERR("get_process_sid failed\n");
  191. return 1;
  192. }
  193. if (!ConvertSidToStringSidW(sid, &sid_string))
  194. {
  195. ERR("ConvertSidToStringSidW failed, error %ld\n", GetLastError());
  196. return 1;
  197. }
  198. output_write(L"\nUSER INFORMATION\n----------------\n\n", -1);
  199. output_write(L"User Name", -1);
  200. for (i = 0; i <= max(wcslen(name), wcslen(L"User Name")) - wcslen(L"User Name"); i++)
  201. output_write(L" ", 1);
  202. output_write(L"SID\n", -1);
  203. for (i = 0; i < wcslen(name); i++)
  204. output_write(L"=", 1);
  205. output_write(L" ", 1);
  206. for (i = 0; i < wcslen(sid_string); i++)
  207. output_write(L"=", 1);
  208. output_write(L"\n", 1);
  209. output_write(name, -1);
  210. output_write(L" ", 1);
  211. output_write(sid_string, -1);
  212. output_write(L"\n", 1);
  213. free(name);
  214. free(sid);
  215. LocalFree(sid_string);
  216. return 0;
  217. }
  218. int __cdecl wmain(int argc, WCHAR *argv[])
  219. {
  220. if (argv[1] == NULL)
  221. {
  222. return simple(NameSamCompatible);
  223. }
  224. else
  225. {
  226. wcslwr(argv[1]);
  227. if (!wcscmp(argv[1], L"/upn"))
  228. {
  229. /* Not implemented as of now, therefore fails */
  230. return simple(NameUserPrincipal);
  231. }
  232. else if (!wcscmp(argv[1], L"/fqdn"))
  233. {
  234. /* Not implemented as of now, therefore fails */
  235. return simple(NameFullyQualifiedDN);
  236. }
  237. else if (!wcscmp(argv[1], L"/logonid"))
  238. {
  239. return logon_id();
  240. }
  241. else if (!wcscmp(argv[1], L"/user"))
  242. {
  243. return user();
  244. }
  245. else
  246. {
  247. FIXME("stub\n");
  248. return 0;
  249. }
  250. }
  251. }