📄 sspi_workbench.cpp
字号:
#include "precomp.h"
#include "transport.h"
#include "model.h"
#include "tokdumpsrv.h"
#include "tokdumpsrv_i.c"
#include "MessageProtection.h"
enum AppStates {
asChoosingSSP,
asChoosingCreds,
asChoosingCtxReq,
asDoneNeedTx,
asNotDoneNeedTx,
asNeedToRx,
asViewingRxToken,
asAuthComplete,
asComposingMsg,
asViewingTxMessage,
asViewingRxMessage,
asSentMessage,
};
static bool s_bServer = false;
static AppStates s_appState = asChoosingSSP;
static MsgProtection s_msgProtection = mpPlain;
static MsgProtection s_msgProtectionUponRx = mpPlain;
static DWORD s_nMsgSequence = 1; // for sequence detection
static DWORD s_grfCtxAttrs = 0;
static Model* s_pModel; // SSPI model
static Transport* s_pTx; // network substrate (TCP)
static BYTE s_msgBuf[4096 * 4]; // a big buffer eliminates buffer management worries
static DWORD s_cbMsg; // length of message
static DWORD s_cbMsgBuf; // length of message + security trailer (signature/encryption info)
static HWND s_hwnd;
static HFONT s_hfontNormal;
static HFONT s_hfontHighlighted;
const wchar_t* const s_pszAppName = L"SSPI Workbench";
const wchar_t* const s_pszINISectionClient = L"client_role";
const wchar_t* const s_pszINISectionServer = L"server_role";
static wchar_t s_szINIPath[_MAX_PATH];
inline const wchar_t* _getINIPath() { return s_szINIPath; }
static const int s_ctlGrp1[] = {
IDC_GROUP_SELECT_SSP,
IDB_SSP_OK,
IDC_SPNEGO,
IDC_PKGLIST,
IDC_CHOOSE_SSP,
IDC_SSP_DROPDOWN,
IDC_STATIC_PROTOCOLS_TO_OFFER,
};
static const int s_ctlGrp2[] = {
IDC_GROUP_CHOOSE_CREDS,
IDB_ACQUIRE_CREDS,
IDC_CRED_CUR_LOGON_SESSION,
IDC_CRED_LOGON_SESSION,
IDC_LOGON_SESSION_ID,
IDC_CRED_EXPLICIT,
IDC_AUTHORITY,
IDC_PRINCIPAL,
IDC_PASSWORD,
IDC_STATIC_LOGONID,
IDC_STATIC_AUTHORITY,
IDC_STATIC_PRINCIPAL,
IDC_STATIC_PASSWORD,
};
static const int s_ctlGrp3a[] = {
IDC_STATIC_SPN,
IDC_SPN,
IDC_STATIC_CTX_REQ,
IDC_MUTUAL_AUTHN,
IDC_DELEGATE,
IDC_PROMPT_FOR_CREDS,
};
static const int s_ctlGrp3b[] = {
IDC_GROUP_AUTHENTICATE,
IDB_INIT_SEC_CTX,
};
static const int s_ctlGrp4[] = {
IDC_GROUP_PROTECT_MESSAGES,
IDB_COMPOSE,
IDB_SIGN,
IDB_ENCRYPT,
IDB_DECRYPT,
IDB_VERIFY_SIG,
};
static const int s_ctlGrp5aClient[] = {
IDC_STATIC_HOST,
IDC_STATIC_PORT,
IDC_HOST_ADDR,
IDC_HOST_PORT,
};
static const int s_ctlGrp5aServer[] = {
IDC_STATIC_PORT,
IDC_HOST_PORT,
};
static const int s_ctlGrp5b[] = {
IDC_GROUP_TXRX,
IDB_TX,
IDB_RX,
};
static const int s_ctlGrp6[] = {
IDB_SIGN,
IDB_ENCRYPT,
};
static const int s_ctlGrp7[] = {
IDB_VERIFY_SIG,
IDB_DECRYPT,
};
struct UIControlGroup {
const int* m_begCtrls;
const int* m_endCtrlsForHighlight;
const int* m_endCtrls;
};
#define MAKE_UI_CONTROL_GROUP(g, n) {g, g + n, g + sizeof g / sizeof *g},
enum UIControlGroups {
uicgChooseSSP,
uicgChooseCred,
uicgChooseCtxReq,
uicgAuthenticate,
uicgProtect,
uicgClientHostInfo,
uicgServerHostInfo,
uicgTxRx,
uicgProtectTx,
uicgProtectRx,
uicgHostInfo, // mapped to uicgClientHostInfo or uicgClientHostInfo
};
static const UIControlGroup g_uiControlGroup[] = {
MAKE_UI_CONTROL_GROUP(s_ctlGrp1, 1)
MAKE_UI_CONTROL_GROUP(s_ctlGrp2, 1)
MAKE_UI_CONTROL_GROUP(s_ctlGrp3a, 0)
MAKE_UI_CONTROL_GROUP(s_ctlGrp3b, 1)
MAKE_UI_CONTROL_GROUP(s_ctlGrp4, 1)
MAKE_UI_CONTROL_GROUP(s_ctlGrp5aClient, 0)
MAKE_UI_CONTROL_GROUP(s_ctlGrp5aServer, 0)
MAKE_UI_CONTROL_GROUP(s_ctlGrp5b, 1)
MAKE_UI_CONTROL_GROUP(s_ctlGrp6, 0)
MAKE_UI_CONTROL_GROUP(s_ctlGrp7, 0)
};
void _err(const wchar_t* psz, bool bRecoverable = false, DWORD err = GetLastError()) {
wchar_t szErr[256];
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
0, err, 0, szErr, sizeof szErr / sizeof *szErr, 0))
wsprintf(szErr, L"Unknown Error: %x", err);
wchar_t szMsg[512];
wsprintf(szMsg, L"%s failed: %s\n\nWould you like to debug?", psz, szErr);
if (IDYES == MessageBox(0, szMsg, s_pszAppName,
MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_YESNOCANCEL)) {
__asm int 3;
}
else if (!bRecoverable)
ExitProcess(err);
}
void _centerWindow(HWND hwnd) {
RECT rc;
GetWindowRect(hwnd, &rc);
SetWindowPos(hwnd, 0,
(GetSystemMetrics(SM_CXSCREEN) - rc.right ) / 2,
(GetSystemMetrics(SM_CYSCREEN) - rc.bottom) / 2,
0, 0,
SWP_NOSIZE | SWP_NOZORDER);
}
void _manageAutoRadioButtonGroup(int nFirstInGroup, int nSelected) {
int id = nFirstInGroup;
HWND hwnd = GetDlgItem(s_hwnd, nFirstInGroup);
for (;;) {
Button_SetCheck(hwnd, id == nSelected ? BST_CHECKED : BST_UNCHECKED);
hwnd = GetWindow(hwnd, GW_HWNDNEXT);
if (GetWindowLong(hwnd, GWL_STYLE) & WS_GROUP)
break;
id = GetWindowLong(hwnd, GWL_ID);
}
}
int _findSelectedAutoRadioButton(int nFirstInGroup) {
int id = nFirstInGroup;
HWND hwnd = GetDlgItem(s_hwnd, nFirstInGroup);
for (;;) {
if (BST_CHECKED == Button_GetCheck(hwnd))
return id;
hwnd = GetWindow(hwnd, GW_HWNDNEXT);
if (GetWindowLong(hwnd, GWL_STYLE) & WS_GROUP)
break;
id = GetWindowLong(hwnd, GWL_ID);
}
return -1;
}
void _highlight(HWND hwnd, bool bHighlight) {
SetWindowFont(hwnd, bHighlight ? s_hfontHighlighted : s_hfontNormal, FALSE);
RECT rc;
GetWindowRect(hwnd, &rc);
MapWindowPoints(0, s_hwnd, (POINT*)&rc, 2);
InvalidateRect(s_hwnd, &rc, TRUE);
}
void _activateControlGroup(UIControlGroups cg, bool bActivate) {
if (uicgHostInfo == cg)
cg = s_bServer ? uicgServerHostInfo : uicgClientHostInfo;
const UIControlGroup& uicg = g_uiControlGroup[int(cg)];
const int* const begin = uicg.m_begCtrls;
const int* const endh = uicg.m_endCtrlsForHighlight;
const int* const end = uicg.m_endCtrls;
const BOOL bEnable = bActivate ? TRUE : FALSE;
bool bHighlighting = true;
for (const int* it = begin; end != it; ++it) {
const HWND hwndCtrl = GetDlgItem(s_hwnd, *it);
if (endh == it)
bHighlighting = false;
if (bHighlighting)
_highlight(hwndCtrl, bActivate);
EnableWindow(hwndCtrl, bEnable);
}
}
void _activateControl(int id, bool bActivate) {
EnableWindow(GetDlgItem(s_hwnd, id), bActivate ? TRUE : FALSE);
}
void _enableComposeInViewer(bool bEnable, bool bSetFocus = false) {
const HWND hwndViewer = GetDlgItem(s_hwnd, IDC_VIEWER);
Edit_SetReadOnly(hwndViewer, bEnable ? FALSE : TRUE);
if (bSetFocus)
SetFocus(hwndViewer);
}
void _syncUIControlState() {
switch (s_appState) {
case asChoosingSSP:
_activateControlGroup(uicgChooseSSP, true);
_activateControlGroup(uicgChooseCred, false);
_activateControlGroup(uicgChooseCtxReq, false);
_activateControlGroup(uicgAuthenticate, false);
_activateControlGroup(uicgProtect, false);
_activateControlGroup(uicgTxRx, false);
_activateControlGroup(uicgClientHostInfo, false);
_activateControlGroup(uicgServerHostInfo, false);
_activateControl(IDB_IMPERSONATE, false);
_activateControl(IDB_CLEAR, false);
switch (_findSelectedAutoRadioButton(IDC_SPNEGO)) {
case IDC_SPNEGO:
SetFocus(GetDlgItem(s_hwnd, IDC_PKGLIST));
break;
case IDC_CHOOSE_SSP:
SetFocus(GetDlgItem(s_hwnd, IDC_SSP_DROPDOWN));
break;
}
break;
case asChoosingCreds:
_activateControlGroup(uicgChooseSSP, false);
_activateControlGroup(uicgChooseCred, true);
switch (_findSelectedAutoRadioButton(IDC_CRED_CUR_LOGON_SESSION)) {
case IDC_CRED_CUR_LOGON_SESSION:
SetFocus(GetDlgItem(s_hwnd, IDC_CRED_CUR_LOGON_SESSION));
break;
case IDC_CRED_LOGON_SESSION:
SetFocus(GetDlgItem(s_hwnd, IDC_LOGON_SESSION_ID));
break;
case IDC_CRED_EXPLICIT:
SetFocus(GetDlgItem(s_hwnd, IDC_AUTHORITY));
break;
}
break;
case asChoosingCtxReq:
_activateControlGroup(uicgChooseCred, false);
_activateControlGroup(uicgChooseCtxReq, true);
_activateControlGroup(uicgAuthenticate, true);
break;
case asDoneNeedTx:
_activateControlGroup(uicgChooseCtxReq, false);
_activateControlGroup(uicgAuthenticate, false);
_activateControlGroup(uicgTxRx, true);
_activateControl(IDB_RX, false);
_activateControl(IDB_TX, true);
if (!s_pTx)
_activateControlGroup(uicgHostInfo, true);
if (s_bServer)
_activateControl(IDB_IMPERSONATE, true);
break;
case asNotDoneNeedTx:
_activateControlGroup(uicgChooseCtxReq, false);
_activateControlGroup(uicgAuthenticate, false);
_activateControlGroup(uicgTxRx, true);
_activateControl(IDB_RX, false);
_activateControl(IDB_TX, true);
if (!s_pTx)
_activateControlGroup(uicgHostInfo, true);
break;
case asNeedToRx:
_activateControlGroup(uicgChooseCred, false);
_activateControlGroup(uicgHostInfo, false);
_activateControl(IDB_TX, false);
_activateControl(IDB_RX, true);
if (!s_pTx)
_activateControlGroup(uicgHostInfo, true);
break;
case asViewingRxToken:
_activateControlGroup(uicgTxRx, false);
_activateControlGroup(uicgAuthenticate, true);
break;
case asAuthComplete:
_activateControlGroup(uicgAuthenticate, false);
_activateControlGroup(uicgProtect, true);
_activateControlGroup(uicgProtectTx, false);
_activateControlGroup(uicgProtectRx, false);
_activateControlGroup(uicgHostInfo, false);
if (s_bServer)
_activateControl(IDB_IMPERSONATE, true);
_activateControl(IDB_CLEAR, false);
_activateControl(IDB_RX, true);
_activateControl(IDB_TX, false);
break;
case asComposingMsg:
_activateControlGroup(uicgProtectTx, true);
_activateControlGroup(uicgProtectRx, false);
_activateControl(IDB_RX, false);
_activateControl(IDB_TX, true);
_activateControl(IDB_COMPOSE, true);
_enableComposeInViewer(true, true);
break;
case asViewingTxMessage:
_activateControl(IDB_COMPOSE, false);
_activateControl(IDB_SIGN, mpPlain == s_msgProtection);
_activateControl(IDB_ENCRYPT, mpPlain == s_msgProtection);
_enableComposeInViewer(false);
break;
case asViewingRxMessage:
_activateControlGroup(uicgTxRx, false);
_activateControlGroup(uicgProtectTx, false);
_activateControlGroup(uicgProtectRx, true);
_activateControl(IDB_COMPOSE, false);
_activateControl(IDB_CLEAR, true);
_activateControl(IDB_VERIFY_SIG, mpSigned == s_msgProtection);
_activateControl(IDB_DECRYPT, mpEncrypted == s_msgProtection);
break;
case asSentMessage:
_activateControlGroup(uicgProtectTx, false);
_activateControl(IDB_COMPOSE, true);
_activateControl(IDB_TX, false);
_activateControl(IDB_RX, true);
_enableComposeInViewer(false);
break;
}
}
bool _chooseSSP() {
wchar_t sz[256];
const wchar_t* pszSSP = 0;
if (BST_CHECKED == Button_GetCheck(GetDlgItem(s_hwnd, IDC_SPNEGO))) {
if (!GetDlgItemText(s_hwnd, IDC_PKGLIST, sz, sizeof sz / sizeof *sz)) {
MessageBox(s_hwnd, L"In order to use SPNEGO, you must enter a comma separated list of SSPs, in order of preference. For example:\n\nKerberos,NTLM", s_pszAppName, MB_SETFOREGROUND | MB_ICONINFORMATION);
return false;
}
s_pModel->chooseSPNEGO(sz);
WritePrivateProfileString(s_pszINISectionClient, L"pkg_list", sz, _getINIPath());
pszSSP = L"Negotiate";
}
else if (BST_CHECKED == Button_GetCheck(GetDlgItem(s_hwnd, IDC_CHOOSE_SSP))) {
HWND hwndList = GetDlgItem(s_hwnd, IDC_SSP_DROPDOWN);
int n = ComboBox_GetCurSel(hwndList);
if (CB_ERR == n)
return false;
if (CB_ERR == ComboBox_GetLBText(hwndList, n, sz))
return false;
s_pModel->chooseSpecificSSP(sz);
pszSSP = sz;
}
else return false;
WritePrivateProfileString(s_pszINISectionClient, L"ssp", pszSSP, _getINIPath());
return true;
}
AppStates _chooseCreds() {
const wchar_t* const pszINISection = s_bServer ? s_pszINISectionServer : s_pszINISectionClient;
const wchar_t* pszCredSource = L"0";
if (BST_CHECKED == Button_GetCheck(GetDlgItem(s_hwnd, IDC_CRED_CUR_LOGON_SESSION))) {
s_pModel->chooseCredentials();
}
else if (BST_CHECKED == Button_GetCheck(GetDlgItem(s_hwnd, IDC_CRED_LOGON_SESSION))) {
wchar_t sz[40];
if (!GetDlgItemText(s_hwnd, IDC_LOGON_SESSION_ID, sz, sizeof sz / sizeof *sz))
return s_appState;
const __int64 n = _wtoi64(sz);
s_pModel->chooseCredentials(reinterpret_cast<const LUID*>(n));
pszCredSource = L"1";
}
else if (BST_CHECKED == Button_GetCheck(GetDlgItem(s_hwnd, IDC_CRED_EXPLICIT))) {
wchar_t szAuthority[256];
wchar_t szPrincipal[256];
wchar_t szPassword[256];
GetDlgItemText(s_hwnd, IDC_AUTHORITY, szAuthority, sizeof szAuthority / sizeof *szAuthority);
GetDlgItemText(s_hwnd, IDC_PRINCIPAL, szPrincipal, sizeof szPrincipal / sizeof *szPrincipal);
GetDlgItemText(s_hwnd, IDC_PASSWORD, szPassword, sizeof szPassword / sizeof *szPassword);
s_pModel->chooseCredentials(szAuthority, szPrincipal, szPassword);
WritePrivateProfileString(pszINISection, L"alt_authority", szAuthority, _getINIPath());
WritePrivateProfileString(pszINISection, L"alt_principal", szPrincipal, _getINIPath());
WritePrivateProfileString(pszINISection, L"alt_password", szPassword, _getINIPath());
pszCredSource = L"2";
}
else return s_appState;
WritePrivateProfileString(pszINISection, L"cred_source", pszCredSource, _getINIPath());
return s_bServer ? asNeedToRx : asChoosingCtxReq;
}
void _updateCtxAttrsViewer() {
static const wchar_t* rgdesc[] = {
L"Delegate",
L"Mutual_auth",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -