Author: akhaldi
Date: Sun Dec 21 23:10:46 2014
New Revision: 65787
URL:
http://svn.reactos.org/svn/reactos?rev=65787&view=rev
Log:
[WHOAMI] Add preliminary version of whoami utility by Ismael Ferreras Morezuelas (with
some changes by me). CORE-8533
Added:
trunk/reactos/base/applications/cmdutils/whoami/
trunk/reactos/base/applications/cmdutils/whoami/CMakeLists.txt (with props)
trunk/reactos/base/applications/cmdutils/whoami/lang/
trunk/reactos/base/applications/cmdutils/whoami/lang/en-US.rc (with props)
trunk/reactos/base/applications/cmdutils/whoami/lang/es-ES.rc (with props)
trunk/reactos/base/applications/cmdutils/whoami/resource.h (with props)
trunk/reactos/base/applications/cmdutils/whoami/whoami.c (with props)
trunk/reactos/base/applications/cmdutils/whoami/whoami.rc (with props)
Modified:
trunk/reactos/base/applications/cmdutils/CMakeLists.txt
Modified: trunk/reactos/base/applications/cmdutils/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils…
==============================================================================
--- trunk/reactos/base/applications/cmdutils/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/reactos/base/applications/cmdutils/CMakeLists.txt [iso-8859-1] Sun Dec 21
23:10:46 2014
@@ -12,6 +12,7 @@
add_subdirectory(sort)
add_subdirectory(taskkill)
add_subdirectory(tree)
+add_subdirectory(whoami)
add_subdirectory(wmic)
add_subdirectory(wscript)
add_subdirectory(xcopy)
Added: trunk/reactos/base/applications/cmdutils/whoami/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils…
==============================================================================
--- trunk/reactos/base/applications/cmdutils/whoami/CMakeLists.txt (added)
+++ trunk/reactos/base/applications/cmdutils/whoami/CMakeLists.txt [iso-8859-1] Sun Dec 21
23:10:46 2014
@@ -0,0 +1,5 @@
+
+add_executable(whoami whoami.c whoami.rc)
+set_module_type(whoami win32cui UNICODE)
+add_importlibs(whoami user32 secur32 advapi32 msvcrt kernel32)
+add_cd_file(TARGET whoami DESTINATION reactos/system32 FOR all)
Propchange: trunk/reactos/base/applications/cmdutils/whoami/CMakeLists.txt
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/base/applications/cmdutils/whoami/lang/en-US.rc
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils…
==============================================================================
--- trunk/reactos/base/applications/cmdutils/whoami/lang/en-US.rc (added)
+++ trunk/reactos/base/applications/cmdutils/whoami/lang/en-US.rc [iso-8859-1] Sun Dec 21
23:10:46 2014
@@ -0,0 +1,56 @@
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+STRINGTABLE
+BEGIN
+ IDS_USER_HEADER "USER INFORMATION"
+ IDS_GROU_HEADER "GROUP INFORMATION"
+ IDS_PRIV_HEADER "PRIVILEGES INFORMATION"
+ IDS_COL_USER_NAME "User Name"
+ IDS_COL_GROUP_NAME "Group Name"
+ IDS_COL_TYPE "Type"
+ IDS_COL_SID "SID"
+ IDS_COL_ATTRIB "Attributes"
+ IDS_COL_PRIV_NAME "Privilege Name"
+ IDS_COL_DESCRIPTION "Description"
+ IDS_COL_STATE "State"
+ IDS_TP_WELL_KNOWN_GROUP "Well-known group"
+ IDS_TP_ALIAS "Alias"
+ IDS_TP_LABEL "Label"
+
+ /* [!] important note from the programmer: the program tries to remove
+ the last ', ' after concatenating, so keep than in mind when translating.
+
+ you can test your translation of these attributes by using 'whoami
/groups' */
+
+ IDS_ATTR_GROUP_MANDATORY "Mandatory group, "
+ IDS_ATTR_GROUP_ENABLED_BY_DEFAULT "Enabled by default, "
+ IDS_ATTR_GROUP_ENABLED "Enabled group, "
+ IDS_ATTR_GROUP_OWNER "Group owner, "
+ IDS_UNKNOWN_DESCRIPTION "???"
+ IDS_STATE_ENABLED "Enabled"
+ IDS_STATE_DISABLED "Disabled"
+ IDS_ERROR_UPN "ERROR: Unable to get User Principal Name (UPN) as the current
logged-on user\nis not a domain user.\n"
+ IDS_ERROR_FQDN "ERROR: Unable to get Fully Qualified Distinguished Name (FQDN)
as the current\nlogged-on user is not a domain user.\n"
+ IDS_ERROR_VALUEXPECTED "ERROR: Invalid syntax. Value expected for
'/fo'.\nType ""WHOAMI /?"" for usage.\n"
+ IDS_ERROR_VALUENOTALLOWED "ERROR: Invalid syntax. '%s' value is not
allowed for '/fo' option.\nType ""WHOAMI /?"" for
usage.\n"
+ IDS_ERROR_1TIMES "ERROR: Invalid syntax. '%s' option is not allowed more
than '1' time(s).\nType ""WHOAMI /?"" for usage.\n"
+ IDS_ERROR_INVALIDSYNTAX "ERROR: Invalid syntax.\nType ""WHOAMI
/?"" for usage.\n"
+ IDS_ERROR_INVALIDARG "ERROR: Invalid argument/option - '%s'.\nType
""WHOAMI /?"" for usage.\n"
+ IDS_ERROR_NH_LIST "ERROR: /NH switch cannot be used with the LIST format.\nType
""WHOAMI /?"" for usage.\n"
+ IDS_HELP "DESCRIPTION:\n\
+ Display user, group and privileges information for the local logged-on
user.\n\
+ If no arguments are provided, displays the current domain and user name.\n\
+ \n\
+ Available output formats for the '/fo' option are 'csv',
'list' and 'table'.\n\
+ Use '/nh' to hide headers. By default the data is displayed in a
table.\n\
+ \n\
+ SYNTAX:\n\
+ whoami [/upn | /fqdn | /logonid] \n\
+ whoami {[/user] [/groups] [/priv]} [/fo <Format>] [/nh] \n\
+ whoami /all [/fo <Format>] [/nh] \n\
+ \n\
+ EXAMPLES: \n\
+ whoami /groups /priv /nh /fo csv \n\
+ whoami /logonid \n\
+ whoami \n"
+END
Propchange: trunk/reactos/base/applications/cmdutils/whoami/lang/en-US.rc
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/base/applications/cmdutils/whoami/lang/es-ES.rc
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils…
==============================================================================
--- trunk/reactos/base/applications/cmdutils/whoami/lang/es-ES.rc (added)
+++ trunk/reactos/base/applications/cmdutils/whoami/lang/es-ES.rc [iso-8859-1] Sun Dec 21
23:10:46 2014
@@ -0,0 +1,58 @@
+/* Spanish translation by Swyter */
+LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
+
+STRINGTABLE
+BEGIN
+ IDS_USER_HEADER "INFORMACIÃN DE USUARIO"
+ IDS_GROU_HEADER "INFORMACIÃN DE GRUPO"
+ IDS_PRIV_HEADER "INFORMACIÃN DE PRIVILEGIOS"
+ IDS_COL_USER_NAME "Nombre de usuario"
+ IDS_COL_GROUP_NAME "Nombre de grupo"
+ IDS_COL_TYPE "Tipo"
+ IDS_COL_SID "SID"
+ IDS_COL_ATTRIB "Atributos"
+ IDS_COL_PRIV_NAME "Nombre de privilegio"
+ IDS_COL_DESCRIPTION "Descripción"
+ IDS_COL_STATE "Estado"
+ IDS_TP_WELL_KNOWN_GROUP "Grupo conocido"
+ IDS_TP_ALIAS "Alias"
+ IDS_TP_LABEL "Etiqueta"
+
+ /* [!] important note from the programmer: the program tries to remove
+ the last ', ' after concatenating, so keep than in mind when translating.
+
+ you can test your translation of these attributes by using 'whoami
/groups' */
+
+ IDS_ATTR_GROUP_MANDATORY "Grupo obligatorio, "
+ IDS_ATTR_GROUP_ENABLED_BY_DEFAULT "Habilitado de manera predeterminada, "
+ IDS_ATTR_GROUP_ENABLED "Grupo habilitado, "
+ IDS_ATTR_GROUP_OWNER "Propietario de grupo, "
+ IDS_UNKNOWN_DESCRIPTION "¿?"
+ IDS_STATE_ENABLED "Habilitada"
+ IDS_STATE_DISABLED "Deshabilitado"
+ IDS_ERROR_UPN "ERROR: no se puede obtener el nombre principal de usuario (UPN)
porque el\nusuario que ha iniciado sesión no es un usuario de dominio.\n"
+ IDS_ERROR_FQDN "ERROR: no se puede obtener el nombre distintivo completo (FQDN)
porque el usuario\nque ha iniciado sesión no es un usuario de dominio.\n"
+ IDS_ERROR_VALUEXPECTED "ERROR: Sintaxis no válida. Se esperaba un valor para
""/fo"".\nEscriba ""WHOAMI /?"" para su
uso.\n"
+ IDS_ERROR_VALUENOTALLOWED "ERROR: Sintaxis no válida. El valor
""%s"" no está permitido para la opción
""/fo"".\nEscriba ""WHOAMI /?"" para su
uso.\n"
+ IDS_ERROR_1TIMES "ERROR: Sintaxis no válida. La opción
""%s"" no está permitida más de ""1""
veces.\nEscriba ""WHOAMI /?"" para su uso.\n"
+ IDS_ERROR_INVALIDSYNTAX "ERROR: sintaxis no válida.\nEscriba ""WHOAMI
/?"" para obtener detalles de uso.\n"
+ IDS_ERROR_INVALIDARG "ERROR: Argumento u opción no válido -
""%s"".\nEscriba ""WHOAMI /?"" para su
uso.\n"
+ IDS_ERROR_NH_LIST "ERROR: no se puede usar el modificador /NH con el formato
LIST.\nEscriba ""WHOAMI /?"" para obtener detalles de uso.\n"
+ IDS_HELP "DESCRIPCIÃN:\n\
+ Muestra información sobre el usuario local, sus privilegios y grupos.\n\
+ Si no se añaden argumentos se mostrará el usuario y dominio actual.\n\
+ \n\
+ Los formatos disponibles para '/fo' son 'csv',
'list' y 'table'.\n\
+ Por defecto los datos se muestran en una tabla (opción
'table').\n\
+ Puedes utilizar '/nh' para ocultar los encabezados. \n\
+ \n\
+ SINTAXIS:\n\
+ whoami [/upn | /fqdn | /logonid] \n\
+ whoami {[/user] [/groups] [/priv]} [/fo <Formato>] [/nh] \n\
+ whoami /all [/fo <Formato>] [/nh] \n\
+ \n\
+ EJEMPLOS: \n\
+ whoami /groups /priv /nh /fo csv \n\
+ whoami /logonid \n\
+ whoami \n"
+END
Propchange: trunk/reactos/base/applications/cmdutils/whoami/lang/es-ES.rc
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/base/applications/cmdutils/whoami/resource.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils…
==============================================================================
--- trunk/reactos/base/applications/cmdutils/whoami/resource.h (added)
+++ trunk/reactos/base/applications/cmdutils/whoami/resource.h [iso-8859-1] Sun Dec 21
23:10:46 2014
@@ -0,0 +1,39 @@
+#pragma once
+
+#define IDS_USER_HEADER 0
+#define IDS_GROU_HEADER 1
+#define IDS_PRIV_HEADER 2
+
+#define IDS_COL_USER_NAME 3
+#define IDS_COL_GROUP_NAME 4
+#define IDS_COL_TYPE 5
+#define IDS_COL_SID 6
+#define IDS_COL_ATTRIB 7
+#define IDS_COL_PRIV_NAME 8
+#define IDS_COL_DESCRIPTION 9
+#define IDS_COL_STATE 10
+
+#define IDS_TP_WELL_KNOWN_GROUP 11
+#define IDS_TP_ALIAS 12
+#define IDS_TP_LABEL 13
+
+#define IDS_ATTR_GROUP_MANDATORY 14
+#define IDS_ATTR_GROUP_ENABLED_BY_DEFAULT 15
+#define IDS_ATTR_GROUP_ENABLED 16
+#define IDS_ATTR_GROUP_OWNER 17
+
+#define IDS_UNKNOWN_DESCRIPTION 18
+
+#define IDS_STATE_ENABLED 19
+#define IDS_STATE_DISABLED 20
+
+#define IDS_ERROR_UPN 21
+#define IDS_ERROR_FQDN 22
+#define IDS_ERROR_VALUEXPECTED 23
+#define IDS_ERROR_VALUENOTALLOWED 24
+#define IDS_ERROR_1TIMES 25
+#define IDS_ERROR_INVALIDSYNTAX 26
+#define IDS_ERROR_INVALIDARG 27
+#define IDS_ERROR_NH_LIST 28
+
+#define IDS_HELP 29
Propchange: trunk/reactos/base/applications/cmdutils/whoami/resource.h
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/base/applications/cmdutils/whoami/whoami.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils…
==============================================================================
--- trunk/reactos/base/applications/cmdutils/whoami/whoami.c (added)
+++ trunk/reactos/base/applications/cmdutils/whoami/whoami.c [iso-8859-1] Sun Dec 21
23:10:46 2014
@@ -0,0 +1,899 @@
+/*
+ * PROJECT: ReactOS Whoami
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: base/applications/cmdutils/whoami/whoami.c
+ * PURPOSE: Displays information about the current local user, groups and
privileges.
+ * PROGRAMMERS: Ismael Ferreras Morezuelas (swyterzone+ros(a)gmail.com)
+ */
+
+
+#define SECURITY_WIN32
+#include <security.h>
+#include <sddl.h>
+
+#include <strsafe.h>
+
+#include "resource.h"
+
+BOOL NoHeader = FALSE;
+UINT NoHeaderArgCount = 0;
+UINT PrintFormatArgCount = 0;
+
+enum
+{
+ undefined,
+ table,
+ list,
+ csv
+} PrintFormat = undefined;
+
+
+BOOL GetArgument(WCHAR* arg, int argc, WCHAR* argv[])
+{
+ int i;
+
+ if (!arg)
+ goto BailOut;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (wcsicmp(argv[i], arg) == 0)
+ return TRUE;
+ }
+
+ BailOut:
+ return FALSE;
+}
+
+/* blanking out the accepted modifiers will make filtering easier later on */
+void BlankArgument(int argc, WCHAR* argv[])
+{
+ argv[argc] = L"";
+}
+
+/* helper functions; let's keep it tidy to avoid redundancies */
+
+LPWSTR WhoamiGetUser(EXTENDED_NAME_FORMAT NameFormat)
+{
+ LPWSTR UsrBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH);
+ ULONG UsrSiz = MAX_PATH;
+
+ if (UsrBuf && GetUserNameExW(NameFormat, UsrBuf, &UsrSiz))
+ {
+ CharLowerW(UsrBuf);
+ return UsrBuf;
+ }
+
+ return NULL;
+}
+
+BOOL WhoamiFree(VOID* Buffer)
+{
+ return HeapFree(GetProcessHeap(), 0, Buffer);
+}
+
+
+VOID* WhoamiGetTokenInfo(TOKEN_INFORMATION_CLASS TokenType)
+{
+ HANDLE hToken = 0;
+ DWORD dwLength = 0;
+ VOID* pTokenInfo = 0;
+
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
+ {
+ GetTokenInformation(hToken,
+ TokenType,
+ NULL,
+ dwLength,
+ &dwLength);
+
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ {
+ pTokenInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
+ if (pTokenInfo == NULL)
+ {
+ wprintf(L"ERROR: not enough memory to allocate the token
structure.\r\n");
+ exit(1);
+ }
+ }
+
+ if (!GetTokenInformation(hToken, TokenType,
+ (LPVOID)pTokenInfo,
+ dwLength,
+ &dwLength))
+ {
+ wprintf(L"ERROR 0x%x: could not get token information.\r\n",
GetLastError());
+ exit(1);
+ }
+
+ CloseHandle(hToken);
+ }
+
+ return pTokenInfo;
+}
+
+LPWSTR WhoamiLoadRcString(INT ResId)
+{
+ #define RC_STRING_MAX_SIZE 850
+ static WCHAR TmpBuffer[RC_STRING_MAX_SIZE];
+
+ LoadStringW(GetModuleHandleW(NULL), ResId, TmpBuffer, RC_STRING_MAX_SIZE);
+
+ return TmpBuffer;
+}
+
+void WhoamiPrintHeader(int HeaderId)
+{
+ PWSTR Header = WhoamiLoadRcString(HeaderId);
+ DWORD Length = wcslen(Header);
+
+ if (NoHeader || PrintFormat == csv)
+ return;
+
+ wprintf(L"\n%s\n", Header);
+
+ while (Length--)
+ wprintf(L"-");
+
+ _putws(L"\n");
+}
+
+typedef struct
+{
+ UINT Rows;
+ UINT Cols;
+ LPWSTR Content[1];
+} WhoamiTable;
+
+/* create and prepare a new table for printing */
+WhoamiTable *WhoamiAllocTable(UINT Rows, UINT Cols)
+{
+ WhoamiTable *pTable = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ sizeof(WhoamiTable) + sizeof(LPWSTR) * Rows * Cols);
+
+ // wprintf(L"DEBUG: Allocating %dx%d elem table for printing.\r\n\r\n",
Rows, Cols);
+
+ if (!pTable)
+ {
+ wprintf(L"ERROR: Not enough memory for displaying the table.");
+ exit(1);
+ }
+
+ pTable->Rows = Rows;
+ pTable->Cols = Cols;
+
+ return pTable;
+}
+
+/* allocate and fill a new entry in the table */
+void WhoamiSetTable(WhoamiTable *pTable, WCHAR *Entry, UINT Row, UINT Col)
+{
+ LPWSTR Target = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ 1 + wcslen(Entry) * sizeof(Entry[0]));
+
+ // wprintf(L"DEBUG: Setting table value '%lp' '%ls' for %lu
%lu.\n", entry, entry, row, col);
+
+ if (!Target)
+ exit(1);
+
+ wcscpy(Target, Entry);
+
+ pTable->Content[Row * pTable->Cols + Col] = Target;
+}
+
+/* fill a new entry in the table */
+void WhoamiSetTableDyn(WhoamiTable *pTable, WCHAR *Entry, UINT Row, UINT Col)
+{
+ pTable->Content[Row * pTable->Cols + Col] = Entry;
+}
+
+/* print and deallocate the table */
+void WhoamiPrintTable(WhoamiTable *pTable)
+{
+ UINT i, j;
+ UINT CurRow, CurCol;
+ UINT *ColLength;
+
+
+ if (!pTable)
+ {
+ wprintf(L"ERROR: The table passed for display is empty.");
+ exit(1);
+ }
+
+ /* if we are going to print a *list* or *table*; take note of the total
+ column size, as we will need it later on when printing them in a tabular
+ fashion, according to their windows counterparts */
+
+ if (PrintFormat != csv)
+ {
+ ColLength = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(UINT) *
pTable->Cols);
+
+ if (PrintFormat == list)
+ {
+ for (j = 0; j < pTable->Cols; j++)
+ if (pTable->Content[j])
+ {
+ UINT ThisLength = wcslen(pTable->Content[j]);
+
+ /* now that we're here, seize the opportunity and add those pesky
":" */
+ pTable->Content[j][ThisLength++] = L':';
+ pTable->Content[j][ThisLength] = UNICODE_NULL;
+
+ ColLength[0] = max(ThisLength, ColLength[0]);
+ }
+ }
+ else
+ {
+ for (j = 0; j < pTable->Cols; j++)
+ for (i = 0; i < pTable->Rows; i++)
+ if (pTable->Content[i * pTable->Cols + j])
+ {
+ UINT ThisLength = wcslen(pTable->Content[i * pTable->Cols +
j]);
+ ColLength[j] = max(ThisLength, ColLength[j]);
+ }
+ }
+ }
+
+ switch (PrintFormat)
+ {
+ case csv:
+ {
+ for (i = 0; i < pTable->Rows; i++)
+ {
+ if (!pTable->Content[i * pTable->Cols])
+ continue;
+
+ /* if the user especified /nh then skip the column labels */
+ if (NoHeader && i == 0)
+ continue;
+
+ for (j = 0; j < pTable->Cols; j++)
+ {
+ if (pTable->Content[i * pTable->Cols + j])
+ {
+ wprintf(L"\"%s\"%s",
+ pTable->Content[i * pTable->Cols + j],
+ (j+1 < pTable->Cols ? L"," :
L""));
+ }
+ }
+ wprintf(L"\n");
+ }
+
+ break;
+
+ }
+
+ case list:
+ {
+ UINT FinalRow = 0;
+
+ /* 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 */
+ for (CurRow = 1; CurRow < pTable->Rows; CurRow++)
+ {
+ /* if the first member of this row isn't available, then forget it
*/
+ if (!pTable->Content[CurRow * pTable->Cols])
+ continue;
+
+ FinalRow = CurRow;
+ }
+
+ for (CurRow = 1; CurRow < pTable->Rows; CurRow++)
+ {
+ /* if the first member of this row isn't available, then forget it
*/
+ if (!pTable->Content[CurRow * pTable->Cols])
+ continue;
+
+ /* if the user especified /nh then skip the column labels */
+ if (NoHeader && i == 0)
+ continue;
+
+ for (CurCol = 0; CurCol < pTable->Cols; CurCol++)
+ {
+ wprintf(L"%-*s %s\n",
+ ColLength[0],
+ pTable->Content[CurCol],
+ pTable->Content[CurRow * pTable->Cols + CurCol]);
+ }
+
+ /* don't add two carriage returns at the very end */
+ if (CurRow != FinalRow)
+ wprintf(L"\n");
+ }
+
+ break;
+ }
+
+
+ case table:
+ default:
+ {
+ for (i = 0; i < pTable->Rows; i++)
+ {
+ /* if the first member of this row isn't available, then forget it
*/
+ if (!pTable->Content[i * pTable->Cols])
+ continue;
+
+ /* if the user especified /nh then skip the column labels too */
+ if (NoHeader && i == 0)
+ continue;
+
+ for (j = 0; j < pTable->Cols; j++)
+ {
+ if (pTable->Content[i * pTable->Cols + j])
+ {
+ wprintf(L"%-*s ", ColLength[j], pTable->Content[i *
pTable->Cols + j]);
+ }
+ }
+ wprintf(L"\n");
+
+ /* add the cute underline thingie for the table header */
+ if (i == 0)
+ {
+ for (j = 0; j < pTable->Cols; j++)
+ {
+ DWORD Length = ColLength[j];
+
+ while (Length--)
+ wprintf(L"=");
+
+ /* a spacing between all the columns except for the last one */
+ if (pTable->Cols != (i + 1))
+ wprintf(L" ");
+ }
+
+ wprintf(L"\n");
+ }
+ }
+
+ }
+ }
+
+ /* fixme: when many tables are displayed in a single run we
+ have to sandwich carriage returns in between. */
+ // if (!final_entry)
+ wprintf(L"\n");
+
+ for (i = 0; i < pTable->Rows; i++)
+ for (j = 0; j < pTable->Cols; j++)
+ WhoamiFree(pTable->Content[i * pTable->Cols + j]);
+
+ WhoamiFree(pTable);
+}
+
+int WhoamiLogonId(void)
+{
+ PTOKEN_GROUPS pGroupInfo = (PTOKEN_GROUPS) WhoamiGetTokenInfo(TokenGroups);
+ DWORD dwIndex = 0;
+ LPWSTR pSidStr = 0;
+ PSID pSid = 0;
+
+ if (pGroupInfo)
+ {
+ /* lets see if we can find the logon SID in that list, should be there */
+ for (dwIndex = 0; dwIndex < pGroupInfo->GroupCount; dwIndex++)
+ {
+ if ((pGroupInfo->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) ==
SE_GROUP_LOGON_ID)
+ {
+ pSid = pGroupInfo->Groups[dwIndex].Sid;
+ }
+ }
+
+ if (!pSid || !ConvertSidToStringSidW(pSid, &pSidStr))
+ {
+ wprintf(L"ERROR: Couldn't convert the logon SID to a
string.\n");
+ return 1;
+ }
+ else
+ {
+ /* let's show our converted logon SID */
+ wprintf(L"%s\n", pSidStr);
+ }
+ }
+
+ /* cleanup our allocations */
+ if (pSidStr)
+ LocalFree(pSidStr);
+
+ if (pGroupInfo)
+ WhoamiFree(pGroupInfo);
+
+ return 0;
+}
+
+int WhoamiUser(void)
+{
+ PTOKEN_USER pUserInfo = (PTOKEN_USER) WhoamiGetTokenInfo(TokenUser);
+ LPWSTR pUserStr = WhoamiGetUser(NameSamCompatible);
+ LPWSTR pSidStr = NULL;
+
+ if (pUserInfo && pUserStr)
+ {
+ WhoamiTable *UserTable = WhoamiAllocTable(2, 2);
+
+ WhoamiPrintHeader(IDS_USER_HEADER);
+
+ /* set the column labels */
+ WhoamiSetTable(UserTable, WhoamiLoadRcString(IDS_COL_USER_NAME), 0, 0);
+ WhoamiSetTable(UserTable, WhoamiLoadRcString(IDS_COL_SID), 0, 1);
+
+ ConvertSidToStringSidW(pUserInfo->User.Sid, &pSidStr);
+
+ /* set the values for our single row of data */
+ WhoamiSetTable(UserTable, pUserStr, 1, 0);
+ WhoamiSetTable(UserTable, pSidStr, 1, 1);
+
+ WhoamiPrintTable(UserTable);
+ }
+ else
+ {
+ return 1;
+ }
+
+ /* cleanup our allocations */
+ if (pSidStr)
+ LocalFree(pSidStr);
+
+ if (pUserInfo)
+ WhoamiFree(pUserInfo);
+
+ if (pUserStr)
+ WhoamiFree(pUserStr);
+
+ return 0;
+}
+
+int WhoamiGroups(void)
+{
+ DWORD dwIndex = 0;
+ LPWSTR pSidStr = 0;
+
+ static WCHAR szGroupName[255] = {0};
+ static WCHAR szDomainName[255] = {0};
+
+ DWORD cchGroupName = _countof(szGroupName);
+ DWORD cchDomainName = _countof(szGroupName);
+
+ SID_NAME_USE Use = 0;
+ BYTE SidNameUseStr[12] =
+ {
+ /* SidTypeUser */ -1,
+ /* SidTypeGroup */ -1,
+ /* SidTypeDomain */ -1,
+ /* SidTypeUser */ -1,
+ /* SidTypeAlias */ IDS_TP_ALIAS,
+ /* SidTypeWellKnownGroup */ IDS_TP_WELL_KNOWN_GROUP,
+ /* SidTypeDeletedAccount */ -1,
+ /* SidTypeInvalid */ -1,
+ /* SidTypeUnknown */ -1,
+ /* SidTypeComputer */ -1,
+ /* SidTypeLabel */ IDS_TP_LABEL
+ };
+
+ PTOKEN_GROUPS pGroupInfo = (PTOKEN_GROUPS)WhoamiGetTokenInfo(TokenGroups);
+
+ if (pGroupInfo)
+ {
+ /* the header is the first (0) row, so we start in the second one (1) */
+ UINT PrintingRow = 1;
+
+ WhoamiTable *GroupTable = WhoamiAllocTable(pGroupInfo->GroupCount + 1, 4);
+
+ WhoamiPrintHeader(IDS_GROU_HEADER);
+
+ WhoamiSetTable(GroupTable, WhoamiLoadRcString(IDS_COL_GROUP_NAME), 0, 0);
+ WhoamiSetTable(GroupTable, WhoamiLoadRcString(IDS_COL_TYPE), 0, 1);
+ WhoamiSetTable(GroupTable, WhoamiLoadRcString(IDS_COL_SID), 0, 2);
+ WhoamiSetTable(GroupTable, WhoamiLoadRcString(IDS_COL_ATTRIB), 0, 3);
+
+ for (dwIndex = 0; dwIndex < pGroupInfo->GroupCount; dwIndex++)
+ {
+ LookupAccountSidW(NULL,
+ pGroupInfo->Groups[dwIndex].Sid,
+ (LPWSTR)&szGroupName,
+ &cchGroupName,
+ (LPWSTR)&szDomainName,
+ &cchDomainName,
+ &Use);
+
+ /* the original tool seems to limit the list to these kind of SID items */
+ if ((Use == SidTypeWellKnownGroup || Use == SidTypeAlias ||
+ Use == SidTypeLabel) &&
!(pGroupInfo->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID))
+ {
+ wchar_t tmpBuffer[666];
+
+ /* looks like windows treats 0x60 as 0x7 for some reason, let's just
nod and call it a day:
+ 0x60 is SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED
+ 0x07 is SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT |
SE_GROUP_ENABLED */
+
+ if (pGroupInfo->Groups[dwIndex].Attributes == 0x60)
+ pGroupInfo->Groups[dwIndex].Attributes = 0x07;
+
+ /* 1- format it as DOMAIN\GROUP if the domain exists, or just GROUP if
not */
+ _snwprintf((LPWSTR)&tmpBuffer,
+ 666,
+ L"%s%s%s",
+ szDomainName,
+ cchDomainName ? L"\\" : L"",
+ szGroupName);
+
+ WhoamiSetTable(GroupTable, tmpBuffer, PrintingRow, 0);
+
+ /* 2- let's find out the group type by using a simple lookup table
for lack of a better method */
+ WhoamiSetTable(GroupTable, WhoamiLoadRcString(SidNameUseStr[Use]),
PrintingRow, 1);
+
+ /* 3- turn that SID into text-form */
+ ConvertSidToStringSidW(pGroupInfo->Groups[dwIndex].Sid,
&pSidStr);
+
+ WhoamiSetTable(GroupTable, pSidStr, PrintingRow, 2);
+
+ LocalFree(pSidStr);
+
+ /* 4- reuse that buffer for appending the attributes in text-form at the
very end */
+ ZeroMemory(tmpBuffer, 666);
+
+ if (pGroupInfo->Groups[dwIndex].Attributes & SE_GROUP_MANDATORY)
+ StringCchCat(tmpBuffer, 666,
WhoamiLoadRcString(IDS_ATTR_GROUP_MANDATORY));
+ if (pGroupInfo->Groups[dwIndex].Attributes &
SE_GROUP_ENABLED_BY_DEFAULT)
+ StringCchCat(tmpBuffer, 666,
WhoamiLoadRcString(IDS_ATTR_GROUP_ENABLED_BY_DEFAULT));
+ if (pGroupInfo->Groups[dwIndex].Attributes & SE_GROUP_ENABLED)
+ StringCchCat(tmpBuffer, 666,
WhoamiLoadRcString(IDS_ATTR_GROUP_ENABLED));
+ if (pGroupInfo->Groups[dwIndex].Attributes & SE_GROUP_OWNER)
+ StringCchCat(tmpBuffer, 666,
WhoamiLoadRcString(IDS_ATTR_GROUP_OWNER));
+
+ /* remove the last comma (', ' which is 2 wchars) of the buffer,
let's keep it simple */
+ tmpBuffer[max(wcslen(tmpBuffer) - 2, 0)] = UNICODE_NULL;
+
+ WhoamiSetTable(GroupTable, tmpBuffer, PrintingRow, 3);
+
+ PrintingRow++;
+ }
+
+ /* reset the buffers so that we can reuse them */
+ ZeroMemory(szGroupName, 255);
+ ZeroMemory(szDomainName, 255);
+
+ cchGroupName = 255;
+ cchDomainName = 255;
+ }
+
+ WhoamiPrintTable(GroupTable);
+ }
+ else
+ {
+ return 1;
+ }
+
+ /* cleanup our allocations */
+ if (pGroupInfo)
+ WhoamiFree((LPVOID)pGroupInfo);
+
+ return 0;
+}
+
+int WhoamiPriv(void)
+{
+ PTOKEN_PRIVILEGES pPrivInfo = (PTOKEN_PRIVILEGES)
WhoamiGetTokenInfo(TokenPrivileges);
+
+ if (pPrivInfo)
+ {
+ DWORD dwResult = 0, dwIndex = 0;
+
+ WhoamiTable *PrivTable = WhoamiAllocTable(pPrivInfo->PrivilegeCount + 1, 3);
+
+ WhoamiPrintHeader(IDS_PRIV_HEADER);
+
+ WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_COL_PRIV_NAME), 0, 0);
+ WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_COL_DESCRIPTION), 0, 1);
+ WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_COL_STATE), 0, 2);
+
+ for (dwIndex = 0; dwIndex < pPrivInfo->PrivilegeCount; dwIndex++)
+ {
+ PWSTR PrivName = NULL, DispName = NULL;
+ DWORD PrivNameSize = 0, DispNameSize = 0;
+ BOOL ret = FALSE;
+
+ ret = LookupPrivilegeNameW(NULL,
+ &pPrivInfo->Privileges[dwIndex].Luid,
+ NULL,
+ &PrivNameSize);
+
+ PrivName = HeapAlloc(GetProcessHeap(), 0, ++PrivNameSize*sizeof(WCHAR));
+
+ LookupPrivilegeNameW(NULL,
+ &pPrivInfo->Privileges[dwIndex].Luid,
+ PrivName,
+ &PrivNameSize);
+
+ WhoamiSetTableDyn(PrivTable, PrivName, dwIndex + 1, 0);
+
+ ret = LookupPrivilegeDisplayNameW(NULL, PrivName, NULL, &DispNameSize,
&dwResult);
+
+ if (!ret || GetLastError() == ERROR_NO_SUCH_PRIVILEGE)
+ {
+ DispName = HeapAlloc(GetProcessHeap(), 0, ++DispNameSize *
sizeof(WCHAR));
+
+ LookupPrivilegeDisplayNameW(NULL, PrivName, DispName, &DispNameSize,
&dwResult);
+
+ //wprintf(L"DispName: %d %x '%s'\n", DispNameSize,
GetLastError(), DispName);
+
+ WhoamiSetTableDyn(PrivTable, DispName, dwIndex + 1, 1);
+ }
+ else
+ {
+ WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_UNKNOWN_DESCRIPTION),
dwIndex + 1, 1);
+ }
+
+ if (pPrivInfo->Privileges[dwIndex].Attributes & SE_PRIVILEGE_ENABLED)
+ WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_STATE_ENABLED), dwIndex
+ 1, 2);
+ else
+ WhoamiSetTable(PrivTable, WhoamiLoadRcString(IDS_STATE_DISABLED), dwIndex
+ 1, 2);
+ }
+
+ WhoamiPrintTable(PrivTable);
+ }
+ else
+ {
+ return 1;
+ }
+
+ /* cleanup our allocations */
+ if (pPrivInfo)
+ WhoamiFree(pPrivInfo);
+
+ return 0;
+}
+
+int wmain(int argc, WCHAR* argv[])
+{
+ INT i;
+ BYTE WamBit = 0;
+
+ #define WAM_USER 1<<0
+ #define WAM_GROUPS 1<<1
+ #define WAM_PRIV 1<<2
+
+
+ /* * * * * * * * * * * * * * * *
+ * A: no parameters whatsoever */
+
+ if (argc == 1)
+ {
+ /* if there's no arguments just choose the simple path and display the
user's identity in lowercase */
+ LPWSTR UserBuffer = WhoamiGetUser(NameSamCompatible);
+
+ if (UserBuffer)
+ {
+ wprintf(L"%s\n", UserBuffer);
+ WhoamiFree(UserBuffer);
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+ /* first things first-- let's detect and manage both printing modifiers (/fo and
/nh) */
+ for (i = 1; i < argc; i++)
+ {
+ if (wcsicmp(argv[i], L"/nh") == 0)
+ {
+ NoHeaderArgCount++;
+
+ if (NoHeader != TRUE)
+ {
+ NoHeader = TRUE;
+ // wprintf(L"Headers disabled!\n");
+ BlankArgument(i, argv);
+ }
+ }
+ }
+
+ for (i = 1; i < argc; i++)
+ {
+ if (wcsicmp(argv[i], L"/fo") == 0)
+ {
+ if ((i + 1) < argc)
+ {
+ // wprintf(L"exists another param after /fo\n");
+
+ PrintFormatArgCount++;
+
+ if (wcsicmp(argv[i + 1], L"table") == 0 && PrintFormat
!= table)
+ {
+ PrintFormat = table;
+ // wprintf(L"Changed to table format\n");
+ BlankArgument(i, argv);
+ BlankArgument(i + 1, argv);
+ }
+ else if (wcsicmp(argv[i + 1], L"list") == 0 &&
PrintFormat != list)
+ {
+ PrintFormat = list;
+ // wprintf(L"Changed to list format\n");
+ BlankArgument(i, argv);
+ BlankArgument(i + 1, argv);
+
+ /* looks like you can't use the "/fo list /nh" options
together
+ for some stupid reason */
+ if (PrintFormat == list && NoHeader == TRUE)
+ {
+ wprintf(WhoamiLoadRcString(IDS_ERROR_NH_LIST));
+ return 1;
+ }
+ }
+ else if (wcsicmp(argv[i + 1], L"csv") == 0 &&
PrintFormat != csv)
+ {
+ PrintFormat = csv;
+ // wprintf(L"Changed to csv format\n");
+ BlankArgument(i, argv);
+ BlankArgument(i + 1, argv);
+ }
+ /* /nh or /fo after /fo isn't parsed as a value */
+ else if (wcsicmp(argv[i + 1], L"/nh") == 0 || wcsicmp(argv[i +
1], L"/fo") == 0
+
+ /* same goes for the other named options, not ideal, but works */
+ || wcsicmp(argv[i + 1], L"/priv") == 0
+ || wcsicmp(argv[i + 1], L"/groups") == 0
+ || wcsicmp(argv[i + 1], L"/user") == 0
+ || wcsicmp(argv[i + 1], L"/all") == 0
+ || wcsicmp(argv[i + 1], L"") == 0)
+ {
+ goto FoValueExpected;
+ }
+ else
+ {
+ wprintf(WhoamiLoadRcString(IDS_ERROR_VALUENOTALLOWED), argv[i + 1]);
+ return 1;
+ }
+ }
+ else
+ {
+ FoValueExpected:
+
+ wprintf(WhoamiLoadRcString(IDS_ERROR_VALUEXPECTED));
+ return 1;
+ }
+ }
+ }
+
+ if (NoHeaderArgCount >= 2)
+ {
+ wprintf(WhoamiLoadRcString(IDS_ERROR_1TIMES), L"/nh");
+ return 1;
+ }
+ /* special case when there's just a /nh as argument; it outputs nothing */
+ else if (NoHeaderArgCount == 1 && argc == 2)
+ {
+ return 0;
+ }
+
+ if (PrintFormatArgCount >= 2)
+ {
+ wprintf(WhoamiLoadRcString(IDS_ERROR_1TIMES), L"/fo");
+ return 1;
+ }
+ /* if there's just /fo <format>... call it invalid */
+ else if (PrintFormatArgCount == 1 && argc == 3)
+ {
+ goto InvalidSyntax;
+ }
+
+ /* * * * * * * * * * * * * *
+ * B: one single parameter */
+
+ if (argc == 2)
+ {
+ /* now let's try to parse the triumvirate of simpler, single (1) arguments...
plus help */
+ if (wcsicmp(argv[1], L"/?") == 0)
+ {
+ wprintf(WhoamiLoadRcString(IDS_HELP));
+ return 0;
+ }
+
+ else if (wcsicmp(argv[1], L"/upn") == 0)
+ {
+ LPWSTR UserBuffer = WhoamiGetUser(NameUserPrincipal);
+
+ if (UserBuffer)
+ {
+ wprintf(L"%s\n", UserBuffer);
+ WhoamiFree(UserBuffer);
+ return 0;
+ }
+ else
+ {
+ wprintf(WhoamiLoadRcString(IDS_ERROR_UPN));
+ return 1;
+ }
+ }
+
+ else if (wcsicmp(argv[1], L"/fqdn") == 0)
+ {
+ LPWSTR UserBuffer = WhoamiGetUser(NameFullyQualifiedDN);
+
+ if (UserBuffer)
+ {
+ wprintf(L"%s\n", UserBuffer);
+ WhoamiFree(UserBuffer);
+ return 0;
+ }
+ else
+ {
+ wprintf(WhoamiLoadRcString(IDS_ERROR_FQDN));
+ return 1;
+ }
+ }
+
+ else if (wcsicmp(argv[1], L"/logonid") == 0)
+ {
+ return WhoamiLogonId();
+ }
+ }
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * C: One main parameter with extra tasty modifiers to play with */
+
+ /* sometimes is just easier to whitelist for lack of a better method */
+ for (i=1; i<argc; i++)
+ {
+ if ((wcsicmp(argv[i], L"/user") != 0) &&
+ (wcsicmp(argv[i], L"/groups") != 0) &&
+ (wcsicmp(argv[i], L"/priv") != 0) &&
+ (wcsicmp(argv[i], L"/all") != 0) &&
+ (wcsicmp(argv[i], L"") != 0))
+ {
+ wprintf(WhoamiLoadRcString(IDS_ERROR_INVALIDARG), argv[i]);
+ return 1;
+ }
+ }
+
+ if (GetArgument(L"/user", argc, argv))
+ {
+ WamBit |= WAM_USER;
+ }
+
+ if (GetArgument(L"/groups", argc, argv))
+ {
+ WamBit |= WAM_GROUPS;
+ }
+
+ if (GetArgument(L"/priv", argc, argv))
+ {
+ WamBit |= WAM_PRIV;
+ }
+
+ if (GetArgument(L"/all", argc, argv))
+ {
+ /* one can't have it /all and any of the other options at the same time */
+ if ((WamBit & (WAM_USER | WAM_GROUPS | WAM_PRIV)) == 0)
+ {
+ WamBit |= (WAM_USER | WAM_GROUPS | WAM_PRIV);
+ }
+ else
+ {
+ goto InvalidSyntax;
+ }
+ }
+
+ if (WamBit & WAM_USER)
+ {
+ WhoamiUser();
+ }
+ if (WamBit & WAM_GROUPS)
+ {
+ WhoamiGroups();
+ }
+ if (WamBit & WAM_PRIV)
+ {
+ WhoamiPriv();
+ }
+
+ return 0;
+
+InvalidSyntax:
+ wprintf(WhoamiLoadRcString(IDS_ERROR_INVALIDSYNTAX));
+ return 1;
+}
Propchange: trunk/reactos/base/applications/cmdutils/whoami/whoami.c
------------------------------------------------------------------------------
svn:eol-style = native
Added: trunk/reactos/base/applications/cmdutils/whoami/whoami.rc
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/applications/cmdutils…
==============================================================================
--- trunk/reactos/base/applications/cmdutils/whoami/whoami.rc (added)
+++ trunk/reactos/base/applications/cmdutils/whoami/whoami.rc [iso-8859-1] Sun Dec 21
23:10:46 2014
@@ -0,0 +1,22 @@
+#include <windef.h>
+
+#include "resource.h"
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+#define REACTOS_STR_FILE_DESCRIPTION "whoami: display information about logged-on
users"
+#define REACTOS_STR_INTERNAL_NAME "whoami"
+#define REACTOS_STR_ORIGINAL_FILENAME "whoami.exe"
+#define REACTOS_STR_COMPANY_NAME "Ismael Ferreras Morezuelas"
+
+#include <reactos/version.rc>
+
+/* UTF-8 */
+#pragma code_page(65001)
+
+#ifdef LANGUAGE_EN_US
+ #include "lang/en-US.rc"
+#endif
+#ifdef LANGUAGE_ES_ES
+ #include "lang/es-ES.rc"
+#endif
Propchange: trunk/reactos/base/applications/cmdutils/whoami/whoami.rc
------------------------------------------------------------------------------
svn:eol-style = native