mirror of
https://github.com/reactos/reactos.git
synced 2025-01-01 03:54:02 +00:00
[WHOAMI] Add preliminary version of whoami utility by Ismael Ferreras Morezuelas (with some changes by me). CORE-8533
svn path=/trunk/; revision=65787
This commit is contained in:
parent
b37505476c
commit
4d592a5c29
7 changed files with 1080 additions and 0 deletions
|
@ -12,6 +12,7 @@ add_subdirectory(reg)
|
|||
add_subdirectory(sort)
|
||||
add_subdirectory(taskkill)
|
||||
add_subdirectory(tree)
|
||||
add_subdirectory(whoami)
|
||||
add_subdirectory(wmic)
|
||||
add_subdirectory(wscript)
|
||||
add_subdirectory(xcopy)
|
||||
|
|
5
reactos/base/applications/cmdutils/whoami/CMakeLists.txt
Normal file
5
reactos/base/applications/cmdutils/whoami/CMakeLists.txt
Normal file
|
@ -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)
|
56
reactos/base/applications/cmdutils/whoami/lang/en-US.rc
Normal file
56
reactos/base/applications/cmdutils/whoami/lang/en-US.rc
Normal file
|
@ -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
|
58
reactos/base/applications/cmdutils/whoami/lang/es-ES.rc
Normal file
58
reactos/base/applications/cmdutils/whoami/lang/es-ES.rc
Normal file
|
@ -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
|
39
reactos/base/applications/cmdutils/whoami/resource.h
Normal file
39
reactos/base/applications/cmdutils/whoami/resource.h
Normal file
|
@ -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
|
899
reactos/base/applications/cmdutils/whoami/whoami.c
Normal file
899
reactos/base/applications/cmdutils/whoami/whoami.c
Normal file
|
@ -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@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;
|
||||
}
|
22
reactos/base/applications/cmdutils/whoami/whoami.rc
Normal file
22
reactos/base/applications/cmdutils/whoami/whoami.rc
Normal file
|
@ -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
|
Loading…
Reference in a new issue