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)
10 #define SECURITY_WIN32
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
, ...)
22 CHAR
*lpBufferA
= NULL
;
23 WCHAR
*lpBufferW
= NULL
;
28 /* first let's find out the final output'ed length of the wprintf routine */
29 va_start(Args
, lpSourceFormatW
);
31 Size
= _vscwprintf(lpSourceFormatW
, Args
);
35 /* allocate a proportional memory chunk taking into account the char width */
36 lpBufferW
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, (Size
+ 1) * sizeof(WCHAR
));
41 /* do wprintf to this newly allocated buffer of ours */
42 va_start(Args
, lpSourceFormatW
);
44 _vsnwprintf(lpBufferW
, Size
, lpSourceFormatW
, Args
);
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
));
53 HeapFree(GetProcessHeap(), 0, lpBufferW
);
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
,
63 /* print the converted OEM string into the console's output and call it a day */
64 printf("%s", lpBufferA
);
66 /* clean everything up */
67 HeapFree(GetProcessHeap(), 0, lpBufferW
);
68 HeapFree(GetProcessHeap(), 0, lpBufferA
);
71 #define wprintf WhoamiOemConversion_printf
73 BOOL NoHeader
= FALSE
;
74 UINT NoHeaderArgCount
= 0;
75 UINT PrintFormatArgCount
= 0;
83 } PrintFormat
= undefined
;
86 BOOL
GetArgument(WCHAR
* arg
, int argc
, WCHAR
* argv
[])
93 for (i
= 1; i
< argc
; i
++)
95 if (wcsicmp(argv
[i
], arg
) == 0)
102 /* blanking out the accepted modifiers will make filtering easier later on */
103 void BlankArgument(int argc
, WCHAR
* argv
[])
108 /* helper functions; let's keep it tidy to avoid redundancies */
110 LPWSTR
WhoamiGetUser(EXTENDED_NAME_FORMAT NameFormat
)
112 LPWSTR UsrBuf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, MAX_PATH
);
113 ULONG UsrSiz
= MAX_PATH
;
118 if (GetUserNameExW(NameFormat
, UsrBuf
, &UsrSiz
))
124 HeapFree(GetProcessHeap(), 0, UsrBuf
);
128 BOOL
WhoamiFree(VOID
* Buffer
)
130 return HeapFree(GetProcessHeap(), 0, Buffer
);
134 VOID
* WhoamiGetTokenInfo(TOKEN_INFORMATION_CLASS TokenType
)
138 VOID
* pTokenInfo
= 0;
140 if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ
, &hToken
))
142 GetTokenInformation(hToken
,
148 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
150 pTokenInfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwLength
);
151 if (pTokenInfo
== NULL
)
153 wprintf(L
"ERROR: not enough memory to allocate the token structure.\r\n");
158 if (!GetTokenInformation(hToken
, TokenType
,
163 wprintf(L
"ERROR 0x%x: could not get token information.\r\n", GetLastError());
164 WhoamiFree(pTokenInfo
);
174 LPWSTR
WhoamiLoadRcString(INT ResId
)
176 #define RC_STRING_MAX_SIZE 850
177 static WCHAR TmpBuffer
[RC_STRING_MAX_SIZE
];
179 LoadStringW(GetModuleHandleW(NULL
), ResId
, TmpBuffer
, RC_STRING_MAX_SIZE
);
184 void WhoamiPrintHeader(int HeaderId
)
186 PWSTR Header
= WhoamiLoadRcString(HeaderId
);
187 DWORD Length
= wcslen(Header
);
189 if (NoHeader
|| PrintFormat
== csv
)
192 wprintf(L
"\n%s\n", Header
);
197 /* _putws seems to be broken in ReactOS' CRT ??? */
208 /* create and prepare a new table for printing */
209 WhoamiTable
*WhoamiAllocTable(UINT Rows
, UINT Cols
)
211 WhoamiTable
*pTable
= HeapAlloc(GetProcessHeap(),
213 sizeof(WhoamiTable
) + sizeof(LPWSTR
) * Rows
* Cols
);
215 // wprintf(L"DEBUG: Allocating %dx%d elem table for printing.\r\n\r\n", Rows, Cols);
219 wprintf(L
"ERROR: Not enough memory for displaying the table.");
229 /* allocate and fill a new entry in the table */
230 void WhoamiSetTable(WhoamiTable
*pTable
, WCHAR
*Entry
, UINT Row
, UINT Col
)
232 LPWSTR Target
= HeapAlloc(GetProcessHeap(),
234 1 + wcslen(Entry
) * sizeof(Entry
[0]));
236 // wprintf(L"DEBUG: Setting table value '%lp' '%ls' for %lu %lu.\n", entry, entry, row, col);
241 wcscpy(Target
, Entry
);
243 pTable
->Content
[Row
* pTable
->Cols
+ Col
] = Target
;
246 /* fill a new entry in the table */
247 void WhoamiSetTableDyn(WhoamiTable
*pTable
, WCHAR
*Entry
, UINT Row
, UINT Col
)
249 pTable
->Content
[Row
* pTable
->Cols
+ Col
] = Entry
;
252 /* print and deallocate the table */
253 void WhoamiPrintTable(WhoamiTable
*pTable
)
262 wprintf(L
"ERROR: The table passed for display is empty.");
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 */
270 if (PrintFormat
!= csv
)
272 ColLength
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(UINT
) * pTable
->Cols
);
274 if (PrintFormat
== list
)
276 for (j
= 0; j
< pTable
->Cols
; j
++)
277 if (pTable
->Content
[j
])
279 UINT ThisLength
= wcslen(pTable
->Content
[j
]);
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
;
285 ColLength
[0] = max(ThisLength
, ColLength
[0]);
290 for (j
= 0; j
< pTable
->Cols
; j
++)
291 for (i
= 0; i
< pTable
->Rows
; i
++)
292 if (pTable
->Content
[i
* pTable
->Cols
+ j
])
294 UINT ThisLength
= wcslen(pTable
->Content
[i
* pTable
->Cols
+ j
]);
295 ColLength
[j
] = max(ThisLength
, ColLength
[j
]);
304 for (i
= 0; i
< pTable
->Rows
; i
++)
306 if (!pTable
->Content
[i
* pTable
->Cols
])
309 /* if the user especified /nh then skip the column labels */
310 if (NoHeader
&& i
== 0)
313 for (j
= 0; j
< pTable
->Cols
; j
++)
315 if (pTable
->Content
[i
* pTable
->Cols
+ j
])
318 pTable
->Content
[i
* pTable
->Cols
+ j
],
319 (j
+1 < pTable
->Cols
? L
"," : L
""));
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
++)
336 /* if the first member of this row isn't available, then forget it */
337 if (!pTable
->Content
[CurRow
* pTable
->Cols
])
343 for (CurRow
= 1; CurRow
< pTable
->Rows
; CurRow
++)
345 /* if the first member of this row isn't available, then forget it */
346 if (!pTable
->Content
[CurRow
* pTable
->Cols
])
349 /* if the user especified /nh then skip the column labels */
350 if (NoHeader
&& i
== 0)
353 for (CurCol
= 0; CurCol
< pTable
->Cols
; CurCol
++)
355 wprintf(L
"%-*s %s\n",
357 pTable
->Content
[CurCol
],
358 pTable
->Content
[CurRow
* pTable
->Cols
+ CurCol
]);
361 /* don't add two carriage returns at the very end */
362 if (CurRow
!= FinalRow
)
373 for (i
= 0; i
< pTable
->Rows
; i
++)
375 /* if the first member of this row isn't available, then forget it */
376 if (!pTable
->Content
[i
* pTable
->Cols
])
379 /* if the user especified /nh then skip the column labels too */
380 if (NoHeader
&& i
== 0)
383 for (j
= 0; j
< pTable
->Cols
; j
++)
385 if (pTable
->Content
[i
* pTable
->Cols
+ j
])
387 wprintf(L
"%-*s ", ColLength
[j
], pTable
->Content
[i
* pTable
->Cols
+ j
]);
392 /* add the cute underline thingie for the table header */
395 for (j
= 0; j
< pTable
->Cols
; j
++)
397 DWORD Length
= ColLength
[j
];
402 /* a spacing between all the columns except for the last one */
403 if (pTable
->Cols
!= (i
+ 1))
414 /* fixme: when many tables are displayed in a single run we
415 have to sandwich carriage returns in between. */
419 for (i
= 0; i
< pTable
->Rows
; i
++)
420 for (j
= 0; j
< pTable
->Cols
; j
++)
421 WhoamiFree(pTable
->Content
[i
* pTable
->Cols
+ j
]);
425 if (PrintFormat
!= csv
)
426 HeapFree(GetProcessHeap(), 0, ColLength
);
429 int WhoamiLogonId(void)
431 PTOKEN_GROUPS pGroupInfo
= (PTOKEN_GROUPS
) WhoamiGetTokenInfo(TokenGroups
);
436 if (pGroupInfo
== NULL
)
439 /* lets see if we can find the logon SID in that list, should be there */
440 for (dwIndex
= 0; dwIndex
< pGroupInfo
->GroupCount
; dwIndex
++)
442 if ((pGroupInfo
->Groups
[dwIndex
].Attributes
& SE_GROUP_LOGON_ID
) == SE_GROUP_LOGON_ID
)
444 pSid
= pGroupInfo
->Groups
[dwIndex
].Sid
;
450 WhoamiFree(pGroupInfo
);
451 wprintf(L
"ERROR: Couldn't find the logon SID.\n");
454 if (!ConvertSidToStringSidW(pSid
, &pSidStr
))
456 WhoamiFree(pGroupInfo
);
457 wprintf(L
"ERROR: Couldn't convert the logon SID to a string.\n");
462 /* let's show our converted logon SID */
463 wprintf(L
"%s\n", pSidStr
);
466 /* cleanup our allocations */
468 WhoamiFree(pGroupInfo
);
475 PTOKEN_USER pUserInfo
= (PTOKEN_USER
) WhoamiGetTokenInfo(TokenUser
);
476 LPWSTR pUserStr
= NULL
;
477 LPWSTR pSidStr
= NULL
;
478 WhoamiTable
*UserTable
= NULL
;
480 if (pUserInfo
== NULL
)
485 pUserStr
= WhoamiGetUser(NameSamCompatible
);
486 if (pUserStr
== NULL
)
488 WhoamiFree(pUserInfo
);
492 UserTable
= WhoamiAllocTable(2, 2);
494 WhoamiPrintHeader(IDS_USER_HEADER
);
496 /* set the column labels */
497 WhoamiSetTable(UserTable
, WhoamiLoadRcString(IDS_COL_USER_NAME
), 0, 0);
498 WhoamiSetTable(UserTable
, WhoamiLoadRcString(IDS_COL_SID
), 0, 1);
500 ConvertSidToStringSidW(pUserInfo
->User
.Sid
, &pSidStr
);
502 /* set the values for our single row of data */
503 WhoamiSetTable(UserTable
, pUserStr
, 1, 0);
504 WhoamiSetTable(UserTable
, pSidStr
, 1, 1);
506 WhoamiPrintTable(UserTable
);
508 /* cleanup our allocations */
510 WhoamiFree(pUserInfo
);
511 WhoamiFree(pUserStr
);
516 int WhoamiGroups(void)
521 static WCHAR szGroupName
[255] = {0};
522 static WCHAR szDomainName
[255] = {0};
524 DWORD cchGroupName
= _countof(szGroupName
);
525 DWORD cchDomainName
= _countof(szGroupName
);
527 SID_NAME_USE Use
= 0;
528 BYTE SidNameUseStr
[12] =
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
543 PTOKEN_GROUPS pGroupInfo
= (PTOKEN_GROUPS
)WhoamiGetTokenInfo(TokenGroups
);
545 WhoamiTable
*GroupTable
= NULL
;
547 if (pGroupInfo
== NULL
)
552 /* the header is the first (0) row, so we start in the second one (1) */
555 GroupTable
= WhoamiAllocTable(pGroupInfo
->GroupCount
+ 1, 4);
557 WhoamiPrintHeader(IDS_GROU_HEADER
);
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);
564 for (dwIndex
= 0; dwIndex
< pGroupInfo
->GroupCount
; dwIndex
++)
566 LookupAccountSidW(NULL
,
567 pGroupInfo
->Groups
[dwIndex
].Sid
,
568 (LPWSTR
)&szGroupName
,
570 (LPWSTR
)&szDomainName
,
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
))
578 wchar_t tmpBuffer
[666];
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 */
584 if (pGroupInfo
->Groups
[dwIndex
].Attributes
== 0x60)
585 pGroupInfo
->Groups
[dwIndex
].Attributes
= 0x07;
587 /* 1- format it as DOMAIN\GROUP if the domain exists, or just GROUP if not */
588 _snwprintf((LPWSTR
)&tmpBuffer
,
592 cchDomainName
? L
"\\" : L
"",
595 WhoamiSetTable(GroupTable
, tmpBuffer
, PrintingRow
, 0);
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);
600 /* 3- turn that SID into text-form */
601 ConvertSidToStringSidW(pGroupInfo
->Groups
[dwIndex
].Sid
, &pSidStr
);
603 WhoamiSetTable(GroupTable
, pSidStr
, PrintingRow
, 2);
607 /* 4- reuse that buffer for appending the attributes in text-form at the very end */
608 ZeroMemory(tmpBuffer
, sizeof(tmpBuffer
));
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
));
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
;
622 WhoamiSetTable(GroupTable
, tmpBuffer
, PrintingRow
, 3);
627 /* reset the buffers so that we can reuse them */
628 ZeroMemory(szGroupName
, sizeof(szGroupName
));
629 ZeroMemory(szDomainName
, sizeof(szDomainName
));
635 WhoamiPrintTable(GroupTable
);
637 /* cleanup our allocations */
638 WhoamiFree((LPVOID
)pGroupInfo
);
645 PTOKEN_PRIVILEGES pPrivInfo
= (PTOKEN_PRIVILEGES
) WhoamiGetTokenInfo(TokenPrivileges
);
646 DWORD dwResult
= 0, dwIndex
= 0;
647 WhoamiTable
*PrivTable
= NULL
;
649 if (pPrivInfo
== NULL
)
654 PrivTable
= WhoamiAllocTable(pPrivInfo
->PrivilegeCount
+ 1, 3);
656 WhoamiPrintHeader(IDS_PRIV_HEADER
);
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);
662 for (dwIndex
= 0; dwIndex
< pPrivInfo
->PrivilegeCount
; dwIndex
++)
664 PWSTR PrivName
= NULL
, DispName
= NULL
;
665 DWORD PrivNameSize
= 0, DispNameSize
= 0;
668 ret
= LookupPrivilegeNameW(NULL
,
669 &pPrivInfo
->Privileges
[dwIndex
].Luid
,
673 PrivName
= HeapAlloc(GetProcessHeap(), 0, ++PrivNameSize
*sizeof(WCHAR
));
675 LookupPrivilegeNameW(NULL
,
676 &pPrivInfo
->Privileges
[dwIndex
].Luid
,
680 WhoamiSetTableDyn(PrivTable
, PrivName
, dwIndex
+ 1, 0);
683 /* try to grab the size of the string, also, beware, as this call is
684 unimplemented in ReactOS/Wine at the moment */
686 LookupPrivilegeDisplayNameW(NULL
, PrivName
, NULL
, &DispNameSize
, &dwResult
);
688 DispName
= HeapAlloc(GetProcessHeap(), 0, ++DispNameSize
* sizeof(WCHAR
));
690 ret
= LookupPrivilegeDisplayNameW(NULL
, PrivName
, DispName
, &DispNameSize
, &dwResult
);
694 // wprintf(L"DispName: %d %x '%s'\n", DispNameSize, GetLastError(), DispName);
695 WhoamiSetTableDyn(PrivTable
, DispName
, dwIndex
+ 1, 1);
699 WhoamiSetTable(PrivTable
, WhoamiLoadRcString(IDS_UNKNOWN_DESCRIPTION
), dwIndex
+ 1, 1);
701 if (DispName
!= NULL
)
702 WhoamiFree(DispName
);
705 if (pPrivInfo
->Privileges
[dwIndex
].Attributes
& SE_PRIVILEGE_ENABLED
)
706 WhoamiSetTable(PrivTable
, WhoamiLoadRcString(IDS_STATE_ENABLED
), dwIndex
+ 1, 2);
708 WhoamiSetTable(PrivTable
, WhoamiLoadRcString(IDS_STATE_DISABLED
), dwIndex
+ 1, 2);
711 WhoamiPrintTable(PrivTable
);
713 /* cleanup our allocations */
714 WhoamiFree(pPrivInfo
);
719 int wmain(int argc
, WCHAR
* argv
[])
724 #define WAM_USER 1<<0
725 #define WAM_GROUPS 1<<1
726 #define WAM_PRIV 1<<2
729 /* * * * * * * * * * * * * * * *
730 * A: no parameters whatsoever */
734 /* if there's no arguments just choose the simple path and display the user's identity in lowercase */
735 LPWSTR UserBuffer
= WhoamiGetUser(NameSamCompatible
);
739 wprintf(L
"%s\n", UserBuffer
);
740 WhoamiFree(UserBuffer
);
749 /* first things first-- let's detect and manage both printing modifiers (/fo and /nh) */
750 for (i
= 1; i
< argc
; i
++)
752 if (wcsicmp(argv
[i
], L
"/nh") == 0)
756 if (NoHeader
== FALSE
)
759 // wprintf(L"Headers disabled!\n");
760 BlankArgument(i
, argv
);
765 for (i
= 1; i
< argc
; i
++)
767 if (wcsicmp(argv
[i
], L
"/fo") == 0)
771 // wprintf(L"exists another param after /fo\n");
773 PrintFormatArgCount
++;
775 if (wcsicmp(argv
[i
+ 1], L
"table") == 0 && PrintFormat
!= table
)
778 // wprintf(L"Changed to table format\n");
779 BlankArgument(i
, argv
);
780 BlankArgument(i
+ 1, argv
);
782 else if (wcsicmp(argv
[i
+ 1], L
"list") == 0 && PrintFormat
!= list
)
785 // wprintf(L"Changed to list format\n");
786 BlankArgument(i
, argv
);
787 BlankArgument(i
+ 1, argv
);
789 /* looks like you can't use the "/fo list /nh" options together
790 for some stupid reason */
791 if (PrintFormat
== list
&& NoHeader
!= FALSE
)
793 wprintf(WhoamiLoadRcString(IDS_ERROR_NH_LIST
));
797 else if (wcsicmp(argv
[i
+ 1], L
"csv") == 0 && PrintFormat
!= csv
)
800 // wprintf(L"Changed to csv format\n");
801 BlankArgument(i
, argv
);
802 BlankArgument(i
+ 1, argv
);
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
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)
814 goto FoValueExpected
;
818 wprintf(WhoamiLoadRcString(IDS_ERROR_VALUENOTALLOWED
), argv
[i
+ 1]);
826 wprintf(WhoamiLoadRcString(IDS_ERROR_VALUEXPECTED
));
832 if (NoHeaderArgCount
>= 2)
834 wprintf(WhoamiLoadRcString(IDS_ERROR_1TIMES
), L
"/nh");
837 /* special case when there's just a /nh as argument; it outputs nothing */
838 else if (NoHeaderArgCount
== 1 && argc
== 2)
843 if (PrintFormatArgCount
>= 2)
845 wprintf(WhoamiLoadRcString(IDS_ERROR_1TIMES
), L
"/fo");
848 /* if there's just /fo <format>... call it invalid */
849 else if (PrintFormatArgCount
== 1 && argc
== 3)
854 /* * * * * * * * * * * * * *
855 * B: one single parameter */
859 /* now let's try to parse the triumvirate of simpler, single (1) arguments... plus help */
860 if (wcsicmp(argv
[1], L
"/?") == 0)
862 wprintf(WhoamiLoadRcString(IDS_HELP
));
866 else if (wcsicmp(argv
[1], L
"/upn") == 0)
868 LPWSTR UserBuffer
= WhoamiGetUser(NameUserPrincipal
);
872 wprintf(L
"%s\n", UserBuffer
);
873 WhoamiFree(UserBuffer
);
878 wprintf(WhoamiLoadRcString(IDS_ERROR_UPN
));
883 else if (wcsicmp(argv
[1], L
"/fqdn") == 0)
885 LPWSTR UserBuffer
= WhoamiGetUser(NameFullyQualifiedDN
);
889 wprintf(L
"%s\n", UserBuffer
);
890 WhoamiFree(UserBuffer
);
895 wprintf(WhoamiLoadRcString(IDS_ERROR_FQDN
));
900 else if (wcsicmp(argv
[1], L
"/logonid") == 0)
902 return WhoamiLogonId();
906 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
907 * C: One main parameter with extra tasty modifiers to play with */
909 /* sometimes is just easier to whitelist for lack of a better method */
910 for (i
=1; i
<argc
; i
++)
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))
918 wprintf(WhoamiLoadRcString(IDS_ERROR_INVALIDARG
), argv
[i
]);
923 if (GetArgument(L
"/user", argc
, argv
))
928 if (GetArgument(L
"/groups", argc
, argv
))
930 WamBit
|= WAM_GROUPS
;
933 if (GetArgument(L
"/priv", argc
, argv
))
938 if (GetArgument(L
"/all", argc
, argv
))
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)
943 WamBit
|= (WAM_USER
| WAM_GROUPS
| WAM_PRIV
);
951 if (WamBit
& WAM_USER
)
955 if (WamBit
& WAM_GROUPS
)
959 if (WamBit
& WAM_PRIV
)
967 wprintf(WhoamiLoadRcString(IDS_ERROR_INVALIDSYNTAX
));