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/CMakeLists.txt?rev=65787&r1=65786&r2=65787&view=diff
==============================================================================
--- 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/whoami/CMakeLists.txt?rev=65787
==============================================================================
--- 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/whoami/lang/en-US.rc?rev=65787
==============================================================================
--- 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/whoami/lang/es-ES.rc?rev=65787
==============================================================================
--- 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/whoami/resource.h?rev=65787
==============================================================================
--- 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/whoami/whoami.c?rev=65787
==============================================================================
--- 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 ([email protected])
+ */
+
+
+#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/whoami/whoami.rc?rev=65787
==============================================================================
--- 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


Reply via email to