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