[WHOAMI]
[reactos.git] / reactos / base / applications / cmdutils / whoami / whoami.c
1 /*
2 * PROJECT: ReactOS Whoami
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/cmdutils/whoami/whoami.c
5 * PURPOSE: Displays information about the current local user, groups and privileges.
6 * PROGRAMMERS: Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
7 */
8
9
10 #define SECURITY_WIN32
11 #include <security.h>
12 #include <sddl.h>
13
14 #include <strsafe.h>
15
16 #include "resource.h"
17
18
19 /* Unicode (W) to ANSI OEM wrapper function, as console and Unicode don't mix well, sigh */
20 static void WhoamiOemConversion_printf(const WCHAR *lpSourceFormatW, ...)
21 {
22 CHAR *lpBufferA = NULL;
23 WCHAR *lpBufferW = NULL;
24
25 UINT Size;
26 va_list Args;
27
28 /* first let's find out the final output'ed length of the wprintf routine */
29 va_start(Args, lpSourceFormatW);
30
31 Size = _vscwprintf(lpSourceFormatW, Args);
32
33 va_end(Args);
34
35 /* allocate a proportional memory chunk taking into account the char width */
36 lpBufferW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (Size + 1) * sizeof(WCHAR));
37
38 if (!lpBufferW)
39 return;
40
41 /* do wprintf to this newly allocated buffer of ours */
42 va_start(Args, lpSourceFormatW);
43
44 _vsnwprintf(lpBufferW, Size, lpSourceFormatW, Args);
45
46 va_end(Args);
47
48 /* allocate a similarly sized buffer for the ANSI/OEM version of our string */
49 lpBufferA = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (Size + 1) * sizeof(CHAR));
50
51 if (!lpBufferA)
52 {
53 HeapFree(GetProcessHeap(), 0, lpBufferW);
54 return;
55 }
56
57 /* convert our Unicode/Wide char string into a proper ANSI/OEM
58 string that our console may understand, at least in theory */
59 CharToOemBuffW(lpBufferW,
60 lpBufferA,
61 Size);
62
63 /* print the converted OEM string into the console's output and call it a day */
64 printf("%s", lpBufferA);
65
66 /* clean everything up */
67 HeapFree(GetProcessHeap(), 0, lpBufferW);
68 HeapFree(GetProcessHeap(), 0, lpBufferA);
69 }
70
71 #define wprintf WhoamiOemConversion_printf
72
73 BOOL NoHeader = FALSE;
74 UINT NoHeaderArgCount = 0;
75 UINT PrintFormatArgCount = 0;
76
77 enum
78 {
79 undefined,
80 table,
81 list,
82 csv
83 } PrintFormat = undefined;
84
85
86 BOOL GetArgument(WCHAR* arg, int argc, WCHAR* argv[])
87 {
88 int i;
89
90 if (!arg)
91 return FALSE;
92
93 for (i = 1; i < argc; i++)
94 {
95 if (wcsicmp(argv[i], arg) == 0)
96 return TRUE;
97 }
98
99 return FALSE;
100 }
101
102 /* blanking out the accepted modifiers will make filtering easier later on */
103 void BlankArgument(int argc, WCHAR* argv[])
104 {
105 argv[argc] = L"";
106 }
107
108 /* helper functions; let's keep it tidy to avoid redundancies */
109
110 LPWSTR WhoamiGetUser(EXTENDED_NAME_FORMAT NameFormat)
111 {
112 LPWSTR UsrBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH);
113 ULONG UsrSiz = MAX_PATH;
114
115 if (UsrBuf == NULL)
116 return NULL;
117
118 if (GetUserNameExW(NameFormat, UsrBuf, &UsrSiz))
119 {
120 CharLowerW(UsrBuf);
121 return UsrBuf;
122 }
123
124 HeapFree(GetProcessHeap(), 0, UsrBuf);
125 return NULL;
126 }
127
128 BOOL WhoamiFree(VOID* Buffer)
129 {
130 return HeapFree(GetProcessHeap(), 0, Buffer);
131 }
132
133
134 VOID* WhoamiGetTokenInfo(TOKEN_INFORMATION_CLASS TokenType)
135 {
136 HANDLE hToken = 0;
137 DWORD dwLength = 0;
138 VOID* pTokenInfo = 0;
139
140 if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
141 {
142 GetTokenInformation(hToken,
143 TokenType,
144 NULL,
145 dwLength,
146 &dwLength);
147
148 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
149 {
150 pTokenInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
151 if (pTokenInfo == NULL)
152 {
153 wprintf(L"ERROR: not enough memory to allocate the token structure.\r\n");
154 exit(1);
155 }
156 }
157
158 if (!GetTokenInformation(hToken, TokenType,
159 (LPVOID)pTokenInfo,
160 dwLength,
161 &dwLength))
162 {
163 wprintf(L"ERROR 0x%x: could not get token information.\r\n", GetLastError());
164 WhoamiFree(pTokenInfo);
165 exit(1);
166 }
167
168 CloseHandle(hToken);
169 }
170
171 return pTokenInfo;
172 }
173
174 LPWSTR WhoamiLoadRcString(INT ResId)
175 {
176 #define RC_STRING_MAX_SIZE 850
177 static WCHAR TmpBuffer[RC_STRING_MAX_SIZE];
178
179 LoadStringW(GetModuleHandleW(NULL), ResId, TmpBuffer, RC_STRING_MAX_SIZE);
180
181 return TmpBuffer;
182 }
183
184 void WhoamiPrintHeader(int HeaderId)
185 {
186 PWSTR Header = WhoamiLoadRcString(HeaderId);
187 DWORD Length = wcslen(Header);
188
189 if (NoHeader || PrintFormat == csv)
190 return;
191
192 wprintf(L"\n%s\n", Header);
193
194 while (Length--)
195 wprintf(L"-");
196
197 /* _putws seems to be broken in ReactOS' CRT ??? */
198 wprintf(L"\n\n");
199 }
200
201 typedef struct
202 {
203 UINT Rows;
204 UINT Cols;
205 LPWSTR Content[1];
206 } WhoamiTable;
207
208 /* create and prepare a new table for printing */
209 WhoamiTable *WhoamiAllocTable(UINT Rows, UINT Cols)
210 {
211 WhoamiTable *pTable = HeapAlloc(GetProcessHeap(),
212 HEAP_ZERO_MEMORY,
213 sizeof(WhoamiTable) + sizeof(LPWSTR) * Rows * Cols);
214
215 // wprintf(L"DEBUG: Allocating %dx%d elem table for printing.\r\n\r\n", Rows, Cols);
216
217 if (!pTable)
218 {
219 wprintf(L"ERROR: Not enough memory for displaying the table.");
220 exit(1);
221 }
222
223 pTable->Rows = Rows;
224 pTable->Cols = Cols;
225
226 return pTable;
227 }
228
229 /* allocate and fill a new entry in the table */
230 void WhoamiSetTable(WhoamiTable *pTable, WCHAR *Entry, UINT Row, UINT Col)
231 {
232 LPWSTR Target = HeapAlloc(GetProcessHeap(),
233 HEAP_ZERO_MEMORY,
234 1 + wcslen(Entry) * sizeof(Entry[0]));
235
236 // wprintf(L"DEBUG: Setting table value '%lp' '%ls' for %lu %lu.\n", entry, entry, row, col);
237
238 if (!Target)
239 exit(1);
240
241 wcscpy(Target, Entry);
242
243 pTable->Content[Row * pTable->Cols + Col] = Target;
244 }
245
246 /* fill a new entry in the table */
247 void WhoamiSetTableDyn(WhoamiTable *pTable, WCHAR *Entry, UINT Row, UINT Col)
248 {
249 pTable->Content[Row * pTable->Cols + Col] = Entry;
250 }
251
252 /* print and deallocate the table */
253 void WhoamiPrintTable(WhoamiTable *pTable)
254 {
255 UINT i, j;
256 UINT CurRow, CurCol;
257 UINT *ColLength;
258
259
260 if (!pTable)
261 {
262 wprintf(L"ERROR: The table passed for display is empty.");
263 exit(1);
264 }
265
266 /* if we are going to print a *list* or *table*; take note of the total
267 column size, as we will need it later on when printing them in a tabular
268 fashion, according to their windows counterparts */
269
270 if (PrintFormat != csv)
271 {
272 ColLength = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(UINT) * pTable->Cols);
273
274 if (PrintFormat == list)
275 {
276 for (j = 0; j < pTable->Cols; j++)
277 if (pTable->Content[j])
278 {
279 UINT ThisLength = wcslen(pTable->Content[j]);
280
281 /* now that we're here, seize the opportunity and add those pesky ":" */
282 pTable->Content[j][ThisLength++] = L':';
283 pTable->Content[j][ThisLength] = UNICODE_NULL;
284
285 ColLength[0] = max(ThisLength, ColLength[0]);
286 }
287 }
288 else
289 {
290 for (j = 0; j < pTable->Cols; j++)
291 for (i = 0; i < pTable->Rows; i++)
292 if (pTable->Content[i * pTable->Cols + j])
293 {
294 UINT ThisLength = wcslen(pTable->Content[i * pTable->Cols + j]);
295 ColLength[j] = max(ThisLength, ColLength[j]);
296 }
297 }
298 }
299
300 switch (PrintFormat)
301 {
302 case csv:
303 {
304 for (i = 0; i < pTable->Rows; i++)
305 {
306 if (!pTable->Content[i * pTable->Cols])
307 continue;
308
309 /* if the user especified /nh then skip the column labels */
310 if (NoHeader && i == 0)
311 continue;
312
313 for (j = 0; j < pTable->Cols; j++)
314 {
315 if (pTable->Content[i * pTable->Cols + j])
316 {
317 wprintf(L"\"%s\"%s",
318 pTable->Content[i * pTable->Cols + j],
319 (j+1 < pTable->Cols ? L"," : L""));
320 }
321 }
322 wprintf(L"\n");
323 }
324
325 break;
326
327 }
328
329 case list:
330 {
331 UINT FinalRow = 0;
332
333 /* fixme: we need to do two passes to find out which entry is the last one shown, or not null this is not exactly optimal */
334 for (CurRow = 1; CurRow < pTable->Rows; CurRow++)
335 {
336 /* if the first member of this row isn't available, then forget it */
337 if (!pTable->Content[CurRow * pTable->Cols])
338 continue;
339
340 FinalRow = CurRow;
341 }
342
343 for (CurRow = 1; CurRow < pTable->Rows; CurRow++)
344 {
345 /* if the first member of this row isn't available, then forget it */
346 if (!pTable->Content[CurRow * pTable->Cols])
347 continue;
348
349 /* if the user especified /nh then skip the column labels */
350 if (NoHeader && i == 0)
351 continue;
352
353 for (CurCol = 0; CurCol < pTable->Cols; CurCol++)
354 {
355 wprintf(L"%-*s %s\n",
356 ColLength[0],
357 pTable->Content[CurCol],
358 pTable->Content[CurRow * pTable->Cols + CurCol]);
359 }
360
361 /* don't add two carriage returns at the very end */
362 if (CurRow != FinalRow)
363 wprintf(L"\n");
364 }
365
366 break;
367 }
368
369
370 case table:
371 default:
372 {
373 for (i = 0; i < pTable->Rows; i++)
374 {
375 /* if the first member of this row isn't available, then forget it */
376 if (!pTable->Content[i * pTable->Cols])
377 continue;
378
379 /* if the user especified /nh then skip the column labels too */
380 if (NoHeader && i == 0)
381 continue;
382
383 for (j = 0; j < pTable->Cols; j++)
384 {
385 if (pTable->Content[i * pTable->Cols + j])
386 {
387 wprintf(L"%-*s ", ColLength[j], pTable->Content[i * pTable->Cols + j]);
388 }
389 }
390 wprintf(L"\n");
391
392 /* add the cute underline thingie for the table header */
393 if (i == 0)
394 {
395 for (j = 0; j < pTable->Cols; j++)
396 {
397 DWORD Length = ColLength[j];
398
399 while (Length--)
400 wprintf(L"=");
401
402 /* a spacing between all the columns except for the last one */
403 if (pTable->Cols != (i + 1))
404 wprintf(L" ");
405 }
406
407 wprintf(L"\n");
408 }
409 }
410
411 }
412 }
413
414 /* fixme: when many tables are displayed in a single run we
415 have to sandwich carriage returns in between. */
416 // if (!final_entry)
417 wprintf(L"\n");
418
419 for (i = 0; i < pTable->Rows; i++)
420 for (j = 0; j < pTable->Cols; j++)
421 WhoamiFree(pTable->Content[i * pTable->Cols + j]);
422
423 WhoamiFree(pTable);
424
425 if (PrintFormat != csv)
426 HeapFree(GetProcessHeap(), 0, ColLength);
427 }
428
429 int WhoamiLogonId(void)
430 {
431 PTOKEN_GROUPS pGroupInfo = (PTOKEN_GROUPS) WhoamiGetTokenInfo(TokenGroups);
432 DWORD dwIndex = 0;
433 LPWSTR pSidStr = 0;
434 PSID pSid = 0;
435
436 if (pGroupInfo == NULL)
437 return 0;
438
439 /* lets see if we can find the logon SID in that list, should be there */
440 for (dwIndex = 0; dwIndex < pGroupInfo->GroupCount; dwIndex++)
441 {
442 if ((pGroupInfo->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
443 {
444 pSid = pGroupInfo->Groups[dwIndex].Sid;
445 }
446 }
447
448 if (pSid == 0)
449 {
450 WhoamiFree(pGroupInfo);
451 wprintf(L"ERROR: Couldn't find the logon SID.\n");
452 return 1;
453 }
454 if (!ConvertSidToStringSidW(pSid, &pSidStr))
455 {
456 WhoamiFree(pGroupInfo);
457 wprintf(L"ERROR: Couldn't convert the logon SID to a string.\n");
458 return 1;
459 }
460 else
461 {
462 /* let's show our converted logon SID */
463 wprintf(L"%s\n", pSidStr);
464 }
465
466 /* cleanup our allocations */
467 LocalFree(pSidStr);
468 WhoamiFree(pGroupInfo);
469
470 return 0;
471 }
472
473 int WhoamiUser(void)
474 {
475 PTOKEN_USER pUserInfo = (PTOKEN_USER) WhoamiGetTokenInfo(TokenUser);
476 LPWSTR pUserStr = NULL;
477 LPWSTR pSidStr = NULL;
478 WhoamiTable *UserTable = NULL;
479
480 if (pUserInfo == NULL)
481 {
482 return 1;
483 }
484
485 pUserStr = WhoamiGetUser(NameSamCompatible);
486 if (pUserStr == NULL)
487 {
488 WhoamiFree(pUserInfo);
489 return 1;
490 }
491
492 UserTable = WhoamiAllocTable(2, 2);
493
494 WhoamiPrintHeader(IDS_USER_HEADER);
495
496 /* set the column labels */
497 WhoamiSetTable(UserTable, WhoamiLoadRcString(IDS_COL_USER_NAME), 0, 0);
498 WhoamiSetTable(UserTable, WhoamiLoadRcString(IDS_COL_SID), 0, 1);
499
500 ConvertSidToStringSidW(pUserInfo->User.Sid, &pSidStr);
501
502 /* set the values for our single row of data */
503 WhoamiSetTable(UserTable, pUserStr, 1, 0);
504 WhoamiSetTable(UserTable, pSidStr, 1, 1);
505
506 WhoamiPrintTable(UserTable);
507
508 /* cleanup our allocations */
509 LocalFree(pSidStr);
510 WhoamiFree(pUserInfo);
511 WhoamiFree(pUserStr);
512
513 return 0;
514 }
515
516 int WhoamiGroups(void)
517 {
518 DWORD dwIndex = 0;
519 LPWSTR pSidStr = 0;
520
521 static WCHAR szGroupName[255] = {0};
522 static WCHAR szDomainName[255] = {0};
523
524 DWORD cchGroupName = _countof(szGroupName);
525 DWORD cchDomainName = _countof(szGroupName);
526
527 SID_NAME_USE Use = 0;
528 BYTE SidNameUseStr[12] =
529 {
530 /* SidTypeUser */ -1,
531 /* SidTypeGroup */ -1,
532 /* SidTypeDomain */ -1,
533 /* SidTypeUser */ -1,
534 /* SidTypeAlias */ IDS_TP_ALIAS,
535 /* SidTypeWellKnownGroup */ IDS_TP_WELL_KNOWN_GROUP,
536 /* SidTypeDeletedAccount */ -1,
537 /* SidTypeInvalid */ -1,
538 /* SidTypeUnknown */ -1,
539 /* SidTypeComputer */ -1,
540 /* SidTypeLabel */ IDS_TP_LABEL
541 };
542
543 PTOKEN_GROUPS pGroupInfo = (PTOKEN_GROUPS)WhoamiGetTokenInfo(TokenGroups);
544 UINT PrintingRow;
545 WhoamiTable *GroupTable = NULL;
546
547 if (pGroupInfo == NULL)
548 {
549 return 1;
550 }
551
552 /* the header is the first (0) row, so we start in the second one (1) */
553 PrintingRow = 1;
554
555 GroupTable = WhoamiAllocTable(pGroupInfo->GroupCount + 1, 4);
556
557 WhoamiPrintHeader(IDS_GROU_HEADER);
558
559 WhoamiSetTable(GroupTable, WhoamiLoadRcString(IDS_COL_GROUP_NAME), 0, 0);
560 WhoamiSetTable(GroupTable, WhoamiLoadRcString(IDS_COL_TYPE), 0, 1);
561 WhoamiSetTable(GroupTable, WhoamiLoadRcString(IDS_COL_SID), 0, 2);
562 WhoamiSetTable(GroupTable, WhoamiLoadRcString(IDS_COL_ATTRIB), 0, 3);
563
564 for (dwIndex = 0; dwIndex < pGroupInfo->GroupCount; dwIndex++)
565 {
566 LookupAccountSidW(NULL,
567 pGroupInfo->Groups[dwIndex].Sid,
568 (LPWSTR)&szGroupName,
569 &cchGroupName,
570 (LPWSTR)&szDomainName,
571 &cchDomainName,
572 &Use);
573
574 /* the original tool seems to limit the list to these kind of SID items */
575 if ((Use == SidTypeWellKnownGroup || Use == SidTypeAlias ||
576 Use == SidTypeLabel) && !(pGroupInfo->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID))
577 {
578 wchar_t tmpBuffer[666];
579
580 /* looks like windows treats 0x60 as 0x7 for some reason, let's just nod and call it a day:
581 0x60 is SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED
582 0x07 is SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED */
583
584 if (pGroupInfo->Groups[dwIndex].Attributes == 0x60)
585 pGroupInfo->Groups[dwIndex].Attributes = 0x07;
586
587 /* 1- format it as DOMAIN\GROUP if the domain exists, or just GROUP if not */
588 _snwprintf((LPWSTR)&tmpBuffer,
589 _countof(tmpBuffer),
590 L"%s%s%s",
591 szDomainName,
592 cchDomainName ? L"\\" : L"",
593 szGroupName);
594
595 WhoamiSetTable(GroupTable, tmpBuffer, PrintingRow, 0);
596
597 /* 2- let's find out the group type by using a simple lookup table for lack of a better method */
598 WhoamiSetTable(GroupTable, WhoamiLoadRcString(SidNameUseStr[Use]), PrintingRow, 1);
599
600 /* 3- turn that SID into text-form */
601 ConvertSidToStringSidW(pGroupInfo->Groups[dwIndex].Sid, &pSidStr);
602
603 WhoamiSetTable(GroupTable, pSidStr, PrintingRow, 2);
604
605 LocalFree(pSidStr);
606
607 /* 4- reuse that buffer for appending the attributes in text-form at the very end */
608 ZeroMemory(tmpBuffer, sizeof(tmpBuffer));
609
610 if (pGroupInfo->Groups[dwIndex].Attributes & SE_GROUP_MANDATORY)
611 StringCchCat(tmpBuffer, _countof(tmpBuffer), WhoamiLoadRcString(IDS_ATTR_GROUP_MANDATORY));
612 if (pGroupInfo->Groups[dwIndex].Attributes & SE_GROUP_ENABLED_BY_DEFAULT)
613 StringCchCat(tmpBuffer, _countof(tmpBuffer), WhoamiLoadRcString(IDS_ATTR_GROUP_ENABLED_BY_DEFAULT));
614 if (pGroupInfo->Groups[dwIndex].Attributes & SE_GROUP_ENABLED)
615 StringCchCat(tmpBuffer, _countof(tmpBuffer), WhoamiLoadRcString(IDS_ATTR_GROUP_ENABLED));
616 if (pGroupInfo->Groups[dwIndex].Attributes & SE_GROUP_OWNER)
617 StringCchCat(tmpBuffer, _countof(tmpBuffer), WhoamiLoadRcString(IDS_ATTR_GROUP_OWNER));
618
619 /* remove the last comma (', ' which is 2 wchars) of the buffer, let's keep it simple */
620 tmpBuffer[max(wcslen(tmpBuffer) - 2, 0)] = UNICODE_NULL;
621
622 WhoamiSetTable(GroupTable, tmpBuffer, PrintingRow, 3);
623
624 PrintingRow++;
625 }
626
627 /* reset the buffers so that we can reuse them */
628 ZeroMemory(szGroupName, sizeof(szGroupName));
629 ZeroMemory(szDomainName, sizeof(szDomainName));
630
631 cchGroupName = 255;
632 cchDomainName = 255;
633 }
634
635 WhoamiPrintTable(GroupTable);
636
637 /* cleanup our allocations */
638 WhoamiFree((LPVOID)pGroupInfo);
639
640 return 0;
641 }
642
643 int WhoamiPriv(void)
644 {
645 PTOKEN_PRIVILEGES pPrivInfo = (PTOKEN_PRIVILEGES) WhoamiGetTokenInfo(TokenPrivileges);
646 DWORD dwResult = 0, dwIndex = 0;
647 WhoamiTable *PrivTable = NULL;
648
649 if (pPrivInfo == NULL)
650 {
651 return 1;
652 }
653
654 PrivTable = WhoamiAllocTable(pPrivInfo->PrivilegeCount + 1, 3);
655
656 WhoamiPrintHeader(IDS_PRIV_HEADER);
657
658 WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_COL_PRIV_NAME), 0, 0);
659 WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_COL_DESCRIPTION), 0, 1);
660 WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_COL_STATE), 0, 2);
661
662 for (dwIndex = 0; dwIndex < pPrivInfo->PrivilegeCount; dwIndex++)
663 {
664 PWSTR PrivName = NULL, DispName = NULL;
665 DWORD PrivNameSize = 0, DispNameSize = 0;
666 BOOL ret = FALSE;
667
668 ret = LookupPrivilegeNameW(NULL,
669 &pPrivInfo->Privileges[dwIndex].Luid,
670 NULL,
671 &PrivNameSize);
672
673 PrivName = HeapAlloc(GetProcessHeap(), 0, ++PrivNameSize*sizeof(WCHAR));
674
675 LookupPrivilegeNameW(NULL,
676 &pPrivInfo->Privileges[dwIndex].Luid,
677 PrivName,
678 &PrivNameSize);
679
680 WhoamiSetTableDyn(PrivTable, PrivName, dwIndex + 1, 0);
681
682
683 /* try to grab the size of the string, also, beware, as this call is
684 unimplemented in ReactOS/Wine at the moment */
685
686 LookupPrivilegeDisplayNameW(NULL, PrivName, NULL, &DispNameSize, &dwResult);
687
688 DispName = HeapAlloc(GetProcessHeap(), 0, ++DispNameSize * sizeof(WCHAR));
689
690 ret = LookupPrivilegeDisplayNameW(NULL, PrivName, DispName, &DispNameSize, &dwResult);
691
692 if (ret && DispName)
693 {
694 // wprintf(L"DispName: %d %x '%s'\n", DispNameSize, GetLastError(), DispName);
695 WhoamiSetTableDyn(PrivTable, DispName, dwIndex + 1, 1);
696 }
697 else
698 {
699 WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_UNKNOWN_DESCRIPTION), dwIndex + 1, 1);
700
701 if (DispName != NULL)
702 WhoamiFree(DispName);
703 }
704
705 if (pPrivInfo->Privileges[dwIndex].Attributes & SE_PRIVILEGE_ENABLED)
706 WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_STATE_ENABLED), dwIndex + 1, 2);
707 else
708 WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_STATE_DISABLED), dwIndex + 1, 2);
709 }
710
711 WhoamiPrintTable(PrivTable);
712
713 /* cleanup our allocations */
714 WhoamiFree(pPrivInfo);
715
716 return 0;
717 }
718
719 int wmain(int argc, WCHAR* argv[])
720 {
721 INT i;
722 BYTE WamBit = 0;
723
724 #define WAM_USER 1<<0
725 #define WAM_GROUPS 1<<1
726 #define WAM_PRIV 1<<2
727
728
729 /* * * * * * * * * * * * * * * *
730 * A: no parameters whatsoever */
731
732 if (argc == 1)
733 {
734 /* if there's no arguments just choose the simple path and display the user's identity in lowercase */
735 LPWSTR UserBuffer = WhoamiGetUser(NameSamCompatible);
736
737 if (UserBuffer)
738 {
739 wprintf(L"%s\n", UserBuffer);
740 WhoamiFree(UserBuffer);
741 return 0;
742 }
743 else
744 {
745 return 1;
746 }
747 }
748
749 /* first things first-- let's detect and manage both printing modifiers (/fo and /nh) */
750 for (i = 1; i < argc; i++)
751 {
752 if (wcsicmp(argv[i], L"/nh") == 0)
753 {
754 NoHeaderArgCount++;
755
756 if (NoHeader == FALSE)
757 {
758 NoHeader = TRUE;
759 // wprintf(L"Headers disabled!\n");
760 BlankArgument(i, argv);
761 }
762 }
763 }
764
765 for (i = 1; i < argc; i++)
766 {
767 if (wcsicmp(argv[i], L"/fo") == 0)
768 {
769 if ((i + 1) < argc)
770 {
771 // wprintf(L"exists another param after /fo\n");
772
773 PrintFormatArgCount++;
774
775 if (wcsicmp(argv[i + 1], L"table") == 0 && PrintFormat != table)
776 {
777 PrintFormat = table;
778 // wprintf(L"Changed to table format\n");
779 BlankArgument(i, argv);
780 BlankArgument(i + 1, argv);
781 }
782 else if (wcsicmp(argv[i + 1], L"list") == 0 && PrintFormat != list)
783 {
784 PrintFormat = list;
785 // wprintf(L"Changed to list format\n");
786 BlankArgument(i, argv);
787 BlankArgument(i + 1, argv);
788
789 /* looks like you can't use the "/fo list /nh" options together
790 for some stupid reason */
791 if (PrintFormat == list && NoHeader != FALSE)
792 {
793 wprintf(WhoamiLoadRcString(IDS_ERROR_NH_LIST));
794 return 1;
795 }
796 }
797 else if (wcsicmp(argv[i + 1], L"csv") == 0 && PrintFormat != csv)
798 {
799 PrintFormat = csv;
800 // wprintf(L"Changed to csv format\n");
801 BlankArgument(i, argv);
802 BlankArgument(i + 1, argv);
803 }
804 /* /nh or /fo after /fo isn't parsed as a value */
805 else if (wcsicmp(argv[i + 1], L"/nh") == 0 || wcsicmp(argv[i + 1], L"/fo") == 0
806
807 /* same goes for the other named options, not ideal, but works */
808 || wcsicmp(argv[i + 1], L"/priv") == 0
809 || wcsicmp(argv[i + 1], L"/groups") == 0
810 || wcsicmp(argv[i + 1], L"/user") == 0
811 || wcsicmp(argv[i + 1], L"/all") == 0
812 || wcsicmp(argv[i + 1], L"") == 0)
813 {
814 goto FoValueExpected;
815 }
816 else
817 {
818 wprintf(WhoamiLoadRcString(IDS_ERROR_VALUENOTALLOWED), argv[i + 1]);
819 return 1;
820 }
821 }
822 else
823 {
824 FoValueExpected:
825
826 wprintf(WhoamiLoadRcString(IDS_ERROR_VALUEXPECTED));
827 return 1;
828 }
829 }
830 }
831
832 if (NoHeaderArgCount >= 2)
833 {
834 wprintf(WhoamiLoadRcString(IDS_ERROR_1TIMES), L"/nh");
835 return 1;
836 }
837 /* special case when there's just a /nh as argument; it outputs nothing */
838 else if (NoHeaderArgCount == 1 && argc == 2)
839 {
840 return 0;
841 }
842
843 if (PrintFormatArgCount >= 2)
844 {
845 wprintf(WhoamiLoadRcString(IDS_ERROR_1TIMES), L"/fo");
846 return 1;
847 }
848 /* if there's just /fo <format>... call it invalid */
849 else if (PrintFormatArgCount == 1 && argc == 3)
850 {
851 goto InvalidSyntax;
852 }
853
854 /* * * * * * * * * * * * * *
855 * B: one single parameter */
856
857 if (argc == 2)
858 {
859 /* now let's try to parse the triumvirate of simpler, single (1) arguments... plus help */
860 if (wcsicmp(argv[1], L"/?") == 0)
861 {
862 wprintf(WhoamiLoadRcString(IDS_HELP));
863 return 0;
864 }
865
866 else if (wcsicmp(argv[1], L"/upn") == 0)
867 {
868 LPWSTR UserBuffer = WhoamiGetUser(NameUserPrincipal);
869
870 if (UserBuffer)
871 {
872 wprintf(L"%s\n", UserBuffer);
873 WhoamiFree(UserBuffer);
874 return 0;
875 }
876 else
877 {
878 wprintf(WhoamiLoadRcString(IDS_ERROR_UPN));
879 return 1;
880 }
881 }
882
883 else if (wcsicmp(argv[1], L"/fqdn") == 0)
884 {
885 LPWSTR UserBuffer = WhoamiGetUser(NameFullyQualifiedDN);
886
887 if (UserBuffer)
888 {
889 wprintf(L"%s\n", UserBuffer);
890 WhoamiFree(UserBuffer);
891 return 0;
892 }
893 else
894 {
895 wprintf(WhoamiLoadRcString(IDS_ERROR_FQDN));
896 return 1;
897 }
898 }
899
900 else if (wcsicmp(argv[1], L"/logonid") == 0)
901 {
902 return WhoamiLogonId();
903 }
904 }
905
906 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
907 * C: One main parameter with extra tasty modifiers to play with */
908
909 /* sometimes is just easier to whitelist for lack of a better method */
910 for (i=1; i<argc; i++)
911 {
912 if ((wcsicmp(argv[i], L"/user") != 0) &&
913 (wcsicmp(argv[i], L"/groups") != 0) &&
914 (wcsicmp(argv[i], L"/priv") != 0) &&
915 (wcsicmp(argv[i], L"/all") != 0) &&
916 (wcsicmp(argv[i], L"") != 0))
917 {
918 wprintf(WhoamiLoadRcString(IDS_ERROR_INVALIDARG), argv[i]);
919 return 1;
920 }
921 }
922
923 if (GetArgument(L"/user", argc, argv))
924 {
925 WamBit |= WAM_USER;
926 }
927
928 if (GetArgument(L"/groups", argc, argv))
929 {
930 WamBit |= WAM_GROUPS;
931 }
932
933 if (GetArgument(L"/priv", argc, argv))
934 {
935 WamBit |= WAM_PRIV;
936 }
937
938 if (GetArgument(L"/all", argc, argv))
939 {
940 /* one can't have it /all and any of the other options at the same time */
941 if ((WamBit & (WAM_USER | WAM_GROUPS | WAM_PRIV)) == 0)
942 {
943 WamBit |= (WAM_USER | WAM_GROUPS | WAM_PRIV);
944 }
945 else
946 {
947 goto InvalidSyntax;
948 }
949 }
950
951 if (WamBit & WAM_USER)
952 {
953 WhoamiUser();
954 }
955 if (WamBit & WAM_GROUPS)
956 {
957 WhoamiGroups();
958 }
959 if (WamBit & WAM_PRIV)
960 {
961 WhoamiPriv();
962 }
963
964 return 0;
965
966 InvalidSyntax:
967 wprintf(WhoamiLoadRcString(IDS_ERROR_INVALIDSYNTAX));
968 return 1;
969 }