wine/programs/klist/main.c

299 lines
9.5 KiB
C
Raw Normal View History

/*
* Copyright 2023 Maxim Karasev <mxkrsv@etersoft.ru>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define WIN32_LEAN_AND_MEAN
#include <ntstatus.h>
#define WIN32_NO_STATUS
#include <windows.h>
#include <ntsecapi.h>
#include "wine/debug.h"
#include "resources.h"
WINE_DEFAULT_DEBUG_CHANNEL(klist);
static WCHAR msg_buf[1024];
static const WCHAR *load_resource(UINT id)
{
LoadStringW(GetModuleHandleW(NULL), id, msg_buf, ARRAY_SIZE(msg_buf));
return msg_buf;
}
static const WCHAR *get_etype_text(LONG encryption_type)
{
switch (encryption_type)
{
case KERB_ETYPE_NULL: return L"NULL";
case KERB_ETYPE_DES_CBC_CRC: return L"DES-CBC-CRC";
case KERB_ETYPE_DES_CBC_MD4: return L"DES-CBC-MD4";
case KERB_ETYPE_DES_CBC_MD5: return L"DES-CBC-MD5";
case KERB_ETYPE_AES128_CTS_HMAC_SHA1_96: return L"AES-128-CTS-HMAC-SHA1-96";
case KERB_ETYPE_AES256_CTS_HMAC_SHA1_96: return L"AES-256-CTS-HMAC-SHA1-96";
case KERB_ETYPE_RC4_MD4: return L"RC4-MD4";
case KERB_ETYPE_RC4_PLAIN2: return L"RC4-PLAIN2";
case KERB_ETYPE_RC4_LM: return L"RC4-LM";
case KERB_ETYPE_RC4_SHA: return L"RC4-SHA";
case KERB_ETYPE_DES_PLAIN: return L"DES-PLAIN";
case KERB_ETYPE_RC4_HMAC_OLD: return L"RC4-HMAC-OLD";
case KERB_ETYPE_RC4_PLAIN_OLD: return L"RC4-PLAIN-OLD";
case KERB_ETYPE_RC4_HMAC_OLD_EXP: return L"RC4-HMAC-OLD-EXP";
case KERB_ETYPE_RC4_PLAIN_OLD_EXP: return L"RC4-PLAIN-OLD-EXP";
case KERB_ETYPE_RC4_PLAIN: return L"RC4-PLAIN";
case KERB_ETYPE_RC4_PLAIN_EXP: return L"RC4-PLAIN-EXP";
case KERB_ETYPE_AES128_CTS_HMAC_SHA1_96_PLAIN: return L"AES-128-CTS-HMAC-SHA1-96-PLAIN";
case KERB_ETYPE_AES256_CTS_HMAC_SHA1_96_PLAIN: return L"AES-256-CTS-HMAC-SHA1-96-PLAIN";
case KERB_ETYPE_DSA_SHA1_CMS: return L"DSA-SHA1-CMS";
case KERB_ETYPE_RSA_MD5_CMS: return L"RSA-MD5-CMS";
case KERB_ETYPE_RSA_SHA1_CMS: return L"RSA-SHA1-CMS";
case KERB_ETYPE_RC2_CBC_ENV: return L"RC2-CBC-ENV";
case KERB_ETYPE_RSA_ENV: return L"RSA-ENV";
case KERB_ETYPE_RSA_ES_OEAP_ENV: return L"RSA-ES-OEAP-ENV";
case KERB_ETYPE_DES_EDE3_CBC_ENV: return L"DES-EDE3-CBC-ENV";
case KERB_ETYPE_DSA_SIGN: return L"DSA-SIGN";
case KERB_ETYPE_DES3_CBC_MD5: return L"DES3-CBC-MD5";
case KERB_ETYPE_DES3_CBC_SHA1: return L"DES3-CBC-SHA1";
case KERB_ETYPE_DES3_CBC_SHA1_KD: return L"DES3-CBC-SHA1-KD";
case KERB_ETYPE_DES_CBC_MD5_NT: return L"DES-CBC-MD5-NT";
case KERB_ETYPE_RC4_HMAC_NT: return L"RC4-HMAC-NT";
case KERB_ETYPE_RC4_HMAC_NT_EXP: return L"RC4-HMAC-NT-EXP";
default: return L"unknown";
}
}
static BOOL get_process_logon_id(LUID *logon_id)
{
HANDLE token_handle;
TOKEN_STATISTICS token_statistics;
DWORD token_statistics_len;
BOOL err;
err = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token_handle);
if (!err)
{
ERR("OpenProcessToken failed\n");
return FALSE;
}
err = GetTokenInformation(token_handle, TokenStatistics, &token_statistics,
sizeof(token_statistics), &token_statistics_len);
if (!err)
{
ERR("GetTokenInformation failed\n");
return FALSE;
}
*logon_id = token_statistics.AuthenticationId;
return TRUE;
}
static void format_dates_and_times(const FILETIME *const filetimes[],
const WCHAR *output_strings[], ULONG count)
{
ULONG i;
for (i = 0; i < count; i++)
{
SYSTEMTIME system_time;
int date_len;
int time_len;
WCHAR *date;
FileTimeToSystemTime(filetimes[i], &system_time);
SystemTimeToTzSpecificLocalTime(NULL, &system_time, &system_time);
date_len = GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_SHORTDATE, &system_time, NULL, NULL, 0, NULL);
time_len = GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, &system_time, NULL, NULL, 0);
date = malloc((date_len + time_len) * sizeof(date[0]));
GetDateFormatEx(LOCALE_NAME_USER_DEFAULT, DATE_SHORTDATE, &system_time, NULL, date, date_len, NULL);
wcscat(date, L" ");
GetTimeFormatEx(LOCALE_NAME_USER_DEFAULT, 0, &system_time, NULL, date + wcslen(date), time_len);
output_strings[i] = date;
}
}
static int tickets(void)
{
LUID logon_id;
BOOL status;
HANDLE lsa_handle;
NTSTATUS err;
ULONG i;
LSA_STRING package_name = {
.Buffer = (char*)MICROSOFT_KERBEROS_NAME_A,
.Length = strlen(MICROSOFT_KERBEROS_NAME_A),
.MaximumLength = strlen(MICROSOFT_KERBEROS_NAME_A),
};
ULONG kerberos_package;
KERB_QUERY_TKT_CACHE_REQUEST kerberos_cache_request = {
.MessageType = KerbQueryTicketCacheMessage,
.LogonId = {0},
};
KERB_QUERY_TKT_CACHE_RESPONSE *kerberos_cache;
ULONG kerberos_cache_size;
NTSTATUS kerberos_call_status;
status = get_process_logon_id(&logon_id);
if (!status)
{
wprintf(load_resource(STRING_UNKNOWN_ERROR));
return 1;
}
err = LsaConnectUntrusted(&lsa_handle);
if (err != STATUS_SUCCESS)
{
wprintf(load_resource(STRING_UNKNOWN_ERROR));
ERR("LsaConnectUntrusted NTSTATUS %lX\n", err);
return 1;
}
err = LsaLookupAuthenticationPackage(lsa_handle, &package_name, &kerberos_package);
if (err != STATUS_SUCCESS)
{
wprintf(load_resource(STRING_UNKNOWN_ERROR));
ERR("LsaLookupAuthenticationPackage NTSTATUS %lX\n", err);
return 1;
}
TRACE("Kerberos LSA package: %lu\n", kerberos_package);
err = LsaCallAuthenticationPackage(lsa_handle, kerberos_package, &kerberos_cache_request,
sizeof(kerberos_cache_request), (PVOID*)&kerberos_cache, &kerberos_cache_size,
&kerberos_call_status);
if (err != STATUS_SUCCESS)
{
wprintf(load_resource(STRING_UNKNOWN_ERROR));
ERR("LsaCallAuthenticationPackage NTSTATUS %lX\n", err);
return 1;
}
wprintf(L"\n");
wprintf(L"%ls %ld:0x%lx\n", load_resource(STRING_LOGON_ID), logon_id.HighPart, logon_id.LowPart);
wprintf(L"\n");
wprintf(L"%ls: (%d)\n", load_resource(STRING_CACHED_TICKETS), kerberos_cache->CountOfTickets);
for (i = 0; i < kerberos_cache->CountOfTickets; i++)
{
KERB_TICKET_CACHE_INFO ticket = kerberos_cache->Tickets[i];
const FILETIME *const filetimes[] = { (FILETIME*)&ticket.StartTime,
(FILETIME*)&ticket.EndTime, (FILETIME*)&ticket.RenewTime };
const WCHAR *dates[3];
format_dates_and_times(filetimes, dates, 3);
wprintf(L"\n");
wprintf(L"#%ld>", i);
wprintf(L" %ls: %.*ls @ %.*ls\n", load_resource(STRING_SERVER),
ticket.ServerName.Length / sizeof(WCHAR), ticket.ServerName.Buffer,
ticket.RealmName.Length / sizeof(WCHAR), ticket.RealmName.Buffer);
wprintf(L" %ls: ", load_resource(STRING_ENCRYPTION_TYPE));
wprintf(L"%s\n", get_etype_text(ticket.EncryptionType));
wprintf(L" %ls: 0x%lx ->", load_resource(STRING_TICKET_FLAGS), ticket.TicketFlags);
#define EXPAND_TICKET_FLAG(x) if (ticket.TicketFlags & KERB_TICKET_FLAGS_##x) wprintf(L" %ls", L ## #x)
EXPAND_TICKET_FLAG(forwardable);
EXPAND_TICKET_FLAG(forwarded);
EXPAND_TICKET_FLAG(proxiable);
EXPAND_TICKET_FLAG(proxy);
EXPAND_TICKET_FLAG(may_postdate);
EXPAND_TICKET_FLAG(postdated);
EXPAND_TICKET_FLAG(invalid);
EXPAND_TICKET_FLAG(renewable);
EXPAND_TICKET_FLAG(initial);
EXPAND_TICKET_FLAG(pre_authent);
EXPAND_TICKET_FLAG(hw_authent);
EXPAND_TICKET_FLAG(ok_as_delegate);
EXPAND_TICKET_FLAG(name_canonicalize);
EXPAND_TICKET_FLAG(cname_in_pa_data);
#undef EXPAND_TICKET_FLAG
wprintf(L"\n");
wprintf(L" %ls: %ls (local)\n", load_resource(STRING_START_TIME), dates[0]);
wprintf(L" %ls: %ls (local)\n", load_resource(STRING_END_TIME), dates[1]);
wprintf(L" %ls: %ls (local)\n", load_resource(STRING_RENEW_TIME), dates[2]);
}
LsaFreeReturnBuffer(kerberos_cache);
LsaDeregisterLogonProcess(lsa_handle);
return 0;
}
static int tgt(void)
{
FIXME("stub\n");
return 0;
}
static int purge(void)
{
FIXME("stub\n");
return 0;
}
static int get(const WCHAR *principal)
{
FIXME("stub\n");
return 0;
}
int __cdecl wmain(int argc, WCHAR *argv[])
{
if (argc < 2)
{
return tickets();
}
if (!wcscmp(argv[1], L"tickets"))
{
return tickets();
}
else if (!wcscmp(argv[1], L"tgt"))
{
return tgt();
}
else if (!wcscmp(argv[1], L"purge"))
{
return purge();
}
else if (!wcscmp(argv[1], L"get"))
{
if (argc < 3)
{
wprintf(load_resource(STRING_USAGE));
return 1;
}
return get(argv[2]);
}
else
{
wprintf(load_resource(STRING_USAGE));
return 1;
}
}