Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

733 lines
18 KiB

/*
* Registry keys for compat:
* HKLM\System\CurrentControlSet\Control\Lsa\Kerberos\Domains
* Keys:
* <Realm>
* Values:
* REG_MULTI_SZ KdcNames
* Names of KDCs for realm
* REG_MULTI_SZ KpasswdNames
* Names of Kpasswd servers for realm
* REG_MULTI_SZ AlternateDomainNames
* Other names for realm (aliases)
* REG_DWORD RealmFlags
* Send address = 1
* TCP Supported = 2
* Delegate ok = 4
* REG_DWORD ApReqChecksumType
* Default AP-REQ checksum type for this realm
* REG_DWORD PreAuthType
* Default preauth type for this realm
*
* HKLM\System\CurrentControlSet\Control\Lsa\Kerberos\UserList
* Each value represents a Kerberos principal to be mapped to
* a local user.
* Values:
* <principal name> : <local user>
* Specific principal to this local user
* <domain name> : <local user>
* All users in this domain to this local user
* '*' : <local user>
* All users to this local user
* '*' : '*'
* All users to a corresponding local user by name
*
* HKLM\System\CurrentControlSet\Control\Lsa\Kerberos
* Values:
* REG_DWORD SkewTime (5 min)
* Clock skew time
* REG_DWORD MaxPacketSize (4000)
* KerbGlobalMaxDatagramSize
* REG_DWORD StartupTime (120 sec)
* REG_DWORD KdcWaitTime (5 sec)
* REG_DWORD KdcBackoffTime (5 sec)
* REG_DWORD KdcSendRetries (3)
* REG_DWORD UseSidCache (False)
* REG_DWORD LogLevel (o)
* KerbGlobalLoggingLevel
* REG_DWORD DefaultEncryptionType (RC4_HMAC)
* KerbGlobalDefaultPreauthEtype - Use this etype
* for preauth data
* REG_DWORD FarKdcTimeout (10 min)
* REG_DWORD StronglyEncryptDatagram (False)
* KerbGlobalUseStrongEncryptionForDatagram
* REG_DWORD MaxReferralCount (6)
* REG_DWORD SupportNewPkinit (True)
*/
//#define UNICODE
//#define _UNICODE
#define STRICT
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <memory.h>
#include <stdlib.h>
#include <string.h>
#define ERR_NDI_LOW_MEM ERROR_NOT_ENOUGH_MEMORY
#define OK ERROR_SUCCESS
#include <commctrl.h>
//#include <winnetwk.h>
#include <stdarg.h>
#define SECURITY_WIN32
#include <security.h>
//#include <ntsecapi.h>
#include <wincrypt.h>
#include <kerbcon.h>
#include <kerbcomm.h>
#include <secpkg.h>
#include <kerbdefs.h>
#include <mitutil.h>
#include "kerbconf.h"
#include "kerbconfres.h"
HINSTANCE hInstance;
krb5_rgy_t *rgy;
LPTSTR default_domain;
BOOL CALLBACK Krb5NdiRealmsProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK AddRealmProc(HWND, UINT, WPARAM, LPARAM);
#define Message(s) \
MessageBox(NULL, s, TEXT("Error"), MB_OK)
#ifdef DBG
#define DPRINTF(s) dprintf s
int debug = 0;
void dprintf(const TCHAR *fmt, ...)
{
static TCHAR szTemp[512];
va_list ap;
va_start (ap, fmt);
wvsprintf(szTemp, fmt, ap);
OutputDebugString(szTemp);
if (debug)
MessageBox(NULL, szTemp, TEXT("Debug"), MB_OK);
va_end (ap);
}
#else
#define DPRINTF(s)
#endif
#define PFREE(p) \
if ((p)) { \
free((p)); \
(p) = NULL; \
}
void
FreeRealm(krb5_realm_t *rp)
{
name_list_t *np, *cp;
np = rp->kdc.lh_first;
while(np) {
cp = np;
np = np->list.le_next;
if (cp->name)
free(cp->name);
free(cp);
}
np = rp->kpasswd.lh_first;
while(np) {
cp = np;
np = np->list.le_next;
if (cp->name)
free(cp->name);
free(cp);
}
np = rp->altname.lh_first;
while(np) {
cp = np;
np = np->list.le_next;
if (cp->name)
free(cp->name);
free(cp);
}
free(rp);
}
void
FreeRgy(krb5_rgy_t *rgy)
{
krb5_realm_t *rp, *crp;
if (rgy) {
rp = rgy->realms.lh_first;
while(rp) {
crp = rp;
rp = rp->list.le_next;
FreeRealm(crp);
}
free(rgy);
}
}
DWORD
RegGetInt(const HKEY hKey, LPCTSTR value)
{
DWORD retCode;
DWORD dwType;
DWORD dataLen;
DWORD keyData;
dataLen = sizeof(keyData);
retCode = RegQueryValueEx(hKey, value, 0,
&dwType, (LPBYTE)&keyData, &dataLen);
if (retCode == ERROR_SUCCESS &&
dwType == REG_DWORD) {
return(keyData);
}
return((DWORD)-1);
}
DWORD
RegSetInt(LPCTSTR key, const DWORD val)
{
HKEY hKey;
DWORD retCode = (DWORD)-1;
retCode = RegCreateKey(HKEY_LOCAL_MACHINE,
REGKEY,
&hKey);
if (retCode == ERROR_SUCCESS) {
retCode = RegSetValueEx(hKey, key, 0,
REG_DWORD, (LPBYTE)&val, sizeof(val));
if (retCode == ERROR_SUCCESS) {
RegCloseKey(hKey);
return(0);
}
}
RegCloseKey(hKey);
return(retCode);
}
LPTSTR
RegGetStr(const HKEY hKey, LPCTSTR value)
{
DWORD retCode;
DWORD dwType;
DWORD dataLen;
LPBYTE keyData = NULL;
dataLen = 0;
retCode = RegQueryValueEx(hKey, value, 0,
&dwType, (LPBYTE)NULL, &dataLen);
if (retCode == ERROR_SUCCESS) {
keyData = malloc(dataLen);
if (!keyData)
return(NULL);
retCode = RegQueryValueEx(hKey, value, 0,
&dwType, keyData, &dataLen);
if (retCode == ERROR_SUCCESS) {
return((LPTSTR)keyData);
}
}
if (keyData)
free(keyData);
return(NULL);
}
DWORD
RegSetStr(LPCTSTR key, LPCTSTR val, INT len)
{
HKEY hKey;
DWORD retCode = (DWORD)-1;
if (len == 0)
len = lstrlen(val) + 1;
retCode = RegCreateKey(HKEY_LOCAL_MACHINE,
REGKEY,
&hKey);
if (retCode == ERROR_SUCCESS) {
retCode = RegSetValueEx(hKey, key, 0,
((lstrlen(val)+1) != len)?
REG_MULTI_SZ:REG_SZ,
(LPBYTE)val, len);
if (retCode == ERROR_SUCCESS) {
RegCloseKey(hKey);
return(0);
}
}
RegCloseKey(hKey);
return(retCode);
}
DWORD
RegDelete(LPCTSTR key)
{
HKEY hKey;
DWORD retCode;
retCode = RegOpenKey(HKEY_LOCAL_MACHINE,
REGKEY,
&hKey);
if (retCode == ERROR_SUCCESS)
retCode = RegDeleteValue(hKey, key);
RegCloseKey(hKey);
return(retCode);
}
LPTSTR
lstrdup(LPCTSTR s)
{
LPTSTR sp;
sp = malloc(lstrlen(s)*sizeof(TCHAR));
if (sp) {
lstrcpy(sp, s);
}
return sp;
}
// Read in krb5 conf properties and attach to ndi object
UINT
Krb5NdiCreate(void)
{
LPTSTR pStr, key;
HKEY hKey, hKeyRealm;
DWORD retCode;
DWORD i, dwVal;
static TCHAR FAR keyValue[255], valData[255];
DWORD keyLen;
PPOLICY_DNS_DOMAIN_INFO DnsDomainInfo = NULL;
rgy = (krb5_rgy_t *)malloc(sizeof(krb5_rgy_t));
if (!rgy)
return ERR_NDI_LOW_MEM;
memset(rgy, 0, sizeof(krb5_rgy_t));
retCode = RegOpenKey(HKEY_LOCAL_MACHINE,
KERB_DOMAINS_KEY,
&hKey);
if (retCode == ERROR_SUCCESS) {
krb5_realm_t *pRealm;
name_list_t *pName;
for (i = 0; retCode == ERROR_SUCCESS; i++) {
keyLen = sizeof(keyValue);
retCode = RegEnumKey(hKey, i, keyValue, keyLen);
if (retCode != ERROR_SUCCESS)
continue;
pRealm = NewRealm(lstrlen(keyValue)+1);
if (!pRealm) {
RegCloseKey(hKey);
return ERR_NDI_LOW_MEM;
}
lstrcpy((LPTSTR)&pRealm->name, keyValue);
key = (LPTSTR)malloc(lstrlen(REGKEY)+10+lstrlen(keyValue));
if (!key) {
RegCloseKey(hKey);
return ERR_NDI_LOW_MEM;
}
lstrcpy(key, KERB_DOMAINS_KEY TEXT("\\"));
lstrcat((LPTSTR)key, keyValue);
retCode = RegOpenKey(HKEY_LOCAL_MACHINE,
key,
&hKeyRealm);
if (retCode == ERROR_SUCCESS) {
pStr = RegGetStr(hKeyRealm, KERB_DOMAIN_KDC_NAMES_VALUE);
while (pStr && *pStr) {
pName = NewNameList();
if (!pName) {
RegCloseKey(hKeyRealm);
RegCloseKey(hKey);
return ERR_NDI_LOW_MEM;
}
pName->name = lstrdup(pStr);
LIST_INSERT_HEAD(&pRealm->kdc, pName, list);
pStr += lstrlen(pStr)+1;
}
pStr = RegGetStr(hKeyRealm, KERB_DOMAIN_KPASSWD_NAMES_VALUE);
while (pStr && *pStr) {
pName = NewNameList();
if (!pName) {
RegCloseKey(hKeyRealm);
RegCloseKey(hKey);
return ERR_NDI_LOW_MEM;
}
pName->name = lstrdup(pStr);
LIST_INSERT_HEAD(&pRealm->kpasswd, pName, list);
pStr += lstrlen(pStr)+1;
}
pStr = RegGetStr(hKeyRealm, KERB_DOMAIN_ALT_NAMES_VALUE);
while (pStr && *pStr) {
pName = NewNameList();
if (!pName) {
RegCloseKey(hKeyRealm);
RegCloseKey(hKey);
return ERR_NDI_LOW_MEM;
}
pName->name = lstrdup(pStr);
LIST_INSERT_HEAD(&pRealm->altname, pName, list);
pStr += lstrlen(pStr)+1;
}
dwVal = RegGetInt(hKeyRealm, KERB_DOMAIN_FLAGS_VALUE);
if (dwVal == -1) {
dwVal = 0;
}
pRealm->realm_flags = dwVal;
dwVal = RegGetInt(hKeyRealm, KERB_DOMAIN_AP_REQ_CSUM_VALUE);
if (dwVal == -1) {
dwVal = KERB_DEFAULT_AP_REQ_CSUM;
}
pRealm->ap_req_chksum = dwVal;
dwVal = RegGetInt(hKeyRealm, KERB_DOMAIN_PREAUTH_VALUE);
if (dwVal == -1) {
dwVal = KERB_DEFAULT_PREAUTH_TYPE;
}
pRealm->preauth_type = dwVal;
RegCloseKey(hKeyRealm);
free(key);
}
LIST_INSERT_HEAD(&rgy->realms, pRealm, list);
}
RegCloseKey(hKey);
//
}
#if 1
retCode = RegOpenKey(HKEY_LOCAL_MACHINE,
TEXT("System\\CurrentControlSet\\Services\\Tcpip\\Parameters"),
&hKey);
if (retCode == ERROR_SUCCESS) {
default_domain = RegGetStr(hKey, TEXT("Domain"));
RegCloseKey(hKey);
}
#else
retCode = LsaQueryInformationPolicy(
LsaHandle,
PolicyDnsDomainInformation,
(PVOID *) &DnsDomainInfo
);
if (!NT_SUCCESS(retCode))
{
printf("Failed to query dns domain info: 0x%x\n",Status);
goto Cleanup;
}
if ( DnsDomainInfo->DnsDomainName.Length == 0 ) {
printf("Machine is not configured to log on to an external KDC. Probably a workgroup member\n");
goto Cleanup;
} else { // nonempty dns domain, but no sid. Assume we're in an RFC1510 domain.
printf( "default realm = %wZ ",
&DnsDomainInfo->DnsDomainName );
if ( DnsDomainInfo->Sid != NULL ) {
printf( "(NT Domain)\n" );
} else {
printf( "(external)\n" );
}
#endif
return OK;
}
/* Write out any conf parameters */
static void
SaveRealm(krb5_realm_t *rp)
{
name_list_t *np;
DPRINTF((TEXT("\n%s: %s\n\t"), rp->name, KERB_DOMAIN_KDC_NAMES_VALUE));
for (np = rp->kdc.lh_first; np; np = np->list.le_next) {
DPRINTF((TEXT("%s "), np->name));
}
DPRINTF((TEXT("\n%s: %s\n\t"), rp->name, KERB_DOMAIN_KPASSWD_NAMES_VALUE));
for (np = rp->kpasswd.lh_first; np; np = np->list.le_next) {
DPRINTF((TEXT("%s "), np->name));
}
DPRINTF((TEXT("\n%s: %s\n\t"), rp->name, KERB_DOMAIN_ALT_NAMES_VALUE));
for (np = rp->altname.lh_first; np; np = np->list.le_next) {
DPRINTF((TEXT("%s "), np->name));
}
DPRINTF((TEXT("\n%s: 0x%x\n"), KERB_DOMAIN_FLAGS_VALUE,
rp->realm_flags));
DPRINTF((TEXT("\n%s: 0x%x\n"), KERB_DOMAIN_AP_REQ_CSUM_VALUE,
rp->ap_req_chksum));
DPRINTF((TEXT("\n%s: 0x%x\n"), KERB_DOMAIN_PREAUTH_VALUE,
rp->preauth_type));
}
UINT
Krb5NdiInstall(krb5_rgy_t *rgy)
{
krb5_realm_t *rp;
if (rgy) {
DPRINTF((TEXT("Realms\n")));
for (rp = rgy->realms.lh_first; rp; rp = rp->list.le_next) {
DPRINTF((TEXT("%s\n"), rp->name));
SaveRealm(rp);
}
}
return OK;
}
/* Destroy any conf parameters */
UINT
Krb5NdiDestroy(krb5_rgy_t *rgy)
{
FreeRgy(rgy);
return OK;
}
void
ShowRealm(HWND hDlg)
{
int idx;
krb5_realm_t *pRealm;
name_list_t *pNlist;
SendDlgItemMessage(hDlg, IDC_REALM_KDC, CB_RESETCONTENT, 0, 0L);
SendDlgItemMessage(hDlg, IDC_REALM_ADMIN, CB_RESETCONTENT, 0, 0L);
SendDlgItemMessage(hDlg, IDC_REALM_ALT_NAMES, CB_RESETCONTENT, 0, 0L);
SetDlgItemText(hDlg, IDC_REALM_DEF_DOMAIN, TEXT(""));
idx = (int)SendDlgItemMessage(hDlg, IDC_REALMS, LB_GETCURSEL, 0, 0L);
if (idx == LB_ERR)
return;
pRealm = (krb5_realm_t FAR *)SendDlgItemMessage(hDlg, IDC_REALMS,
LB_GETITEMDATA, idx, 0L);
for (pNlist = pRealm->kdc.lh_first; pNlist; pNlist = pNlist->list.le_next) {
idx = SendDlgItemMessage(hDlg, IDC_REALM_KDC, CB_ADDSTRING, 0,
(LPARAM)pNlist->name);
SetDlgItemText(hDlg, IDC_REALM_KDC, pNlist->name);
SendDlgItemMessage(hDlg, IDC_REALM_KDC, CB_SETITEMDATA, idx,
(LPARAM)(name_list_t FAR *)pNlist);
}
for (pNlist = pRealm->kpasswd.lh_first; pNlist; pNlist = pNlist->list.le_next) {
idx = SendDlgItemMessage(hDlg, IDC_REALM_ADMIN, CB_ADDSTRING, 0,
(LPARAM)pNlist->name);
SetDlgItemText(hDlg, IDC_REALM_ADMIN, pNlist->name);
SendDlgItemMessage(hDlg, IDC_REALM_ADMIN, CB_SETITEMDATA, idx,
(LPARAM)(name_list_t FAR *)pNlist);
}
for (pNlist = pRealm->altname.lh_first; pNlist; pNlist = pNlist->list.le_next) {
idx = SendDlgItemMessage(hDlg, IDC_REALM_ALT_NAMES, CB_ADDSTRING, 0,
(LPARAM)pNlist->name);
SetDlgItemText(hDlg, IDC_REALM_ALT_NAMES, pNlist->name);
SendDlgItemMessage(hDlg, IDC_REALM_ALT_NAMES, CB_SETITEMDATA, idx,
(LPARAM)(name_list_t FAR *)pNlist);
}
CheckDlgButton(hDlg, IDC_KDC_TCP,
(pRealm->realm_flags & KERB_MIT_REALM_TCP_SUPPORTED)?
BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(hDlg, IDC_ADDRREQ,
(pRealm->realm_flags & KERB_MIT_REALM_SEND_ADDRESS)?
BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(hDlg, IDC_KDC_DELEG,
(pRealm->realm_flags & KERB_MIT_REALM_TRUSTED_FOR_DELEGATION)?
BST_CHECKED:BST_UNCHECKED);
CheckDlgButton(hDlg, IDC_KDC_CANONICALIZE,
(pRealm->realm_flags & KERB_MIT_REALM_DOES_CANONICALIZE)?
BST_CHECKED:BST_UNCHECKED);
SetDlgItemInt(hDlg, IDC_CHKSUM, pRealm->ap_req_chksum, FALSE);
SetDlgItemText(hDlg, IDC_REALM_DEF_DOMAIN,
STRDEF(default_domain, TEXT("")));
}
BOOL CALLBACK
AddRealmProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
TCHAR realm_name[255];
krb5_realm_t *pRealm;
switch (message) {
case WM_INITDIALOG:
SetFocus(GetDlgItem(hDlg, IDC_NEW_REALM));
return 0;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
GetDlgItemText(hDlg, IDC_NEW_REALM,
realm_name, sizeof(realm_name));
pRealm = NewRealm(lstrlen(realm_name));
if (pRealm)
lstrcpy(pRealm->name, realm_name);
EndDialog(hDlg, (int)pRealm);
return TRUE;
case IDCANCEL:
EndDialog(hDlg, 0);
return TRUE;
}
break;
}
return FALSE;
}
void
AddRealm(HWND hDlg, krb5_rgy_t *rgy)
{
krb5_realm_t *pRealm;
if (pRealm = (krb5_realm_t *) DialogBox(hInstance,
MAKEINTRESOURCE(IDD_REALM_ADD),
hDlg,
AddRealmProc)) {
int idx;
LIST_INSERT_HEAD(&rgy->realms, pRealm, list);
idx = SendDlgItemMessage(hDlg, IDC_REALMS, LB_ADDSTRING, 0,
(LPARAM)(LPSTR)pRealm->name);
SendDlgItemMessage(hDlg, IDC_REALMS, LB_SETITEMDATA, idx,
(LPARAM)(krb5_realm_t FAR *)pRealm);
SendDlgItemMessage(hDlg, IDC_REALMS, LB_SETCURSEL, idx, 0L);
ShowRealm(hDlg);
}
}
void
RemoveRealm(HWND hDlg)
{
TCHAR *msg;
int idx;
krb5_realm_t *pRealm;
idx = (int) SendDlgItemMessage(hDlg, IDC_REALMS, LB_GETCURSEL, 0, 0L);
pRealm = (krb5_realm_t FAR *)SendDlgItemMessage(hDlg, IDC_REALMS,
LB_GETITEMDATA, idx, 0L);
#define FMT TEXT("You are about to remove the realm \"%s\"\n\rDo you want to continue ?")
msg = malloc(lstrlen(FMT) + lstrlen(pRealm->name));
if (!msg)
return;
wsprintf(msg, FMT, pRealm->name);
#undef FMT
if (MessageBox(hDlg, msg, TEXT("Confirm Delete"),
MB_YESNO|MB_ICONEXCLAMATION|MB_DEFBUTTON2|MB_SETFOREGROUND) == IDYES) {
idx = SendDlgItemMessage(hDlg, IDC_REALMS, LB_DELETESTRING, idx, 0L);
LIST_REMOVE(pRealm, list);
FreeRealm(pRealm);
SendDlgItemMessage(hDlg, IDC_REALMS, CB_SETCURSEL, 0, 0L);
ShowRealm(hDlg);
}
free(msg);
}
BOOL CALLBACK
Krb5NdiRealmsProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static PROPSHEETPAGE *ps;
krb5_realm_t *pRealm;
switch (message) {
case WM_INITDIALOG:
for (pRealm = rgy->realms.lh_first; pRealm; pRealm = pRealm->list.le_next) {
int idx = SendDlgItemMessage(hDlg, IDC_REALMS, LB_ADDSTRING, 0,
(LPARAM)(LPSTR)pRealm->name);
SendDlgItemMessage(hDlg, IDC_REALMS, LB_SETITEMDATA, idx,
(LPARAM)(krb5_realm_t FAR *)pRealm);
}
SendDlgItemMessage(hDlg, IDC_REALMS, LB_SETCURSEL, 0, 0L);
ShowRealm(hDlg);
ps = (PROPSHEETPAGE *)lParam;
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_REALMS:
switch (HIWORD(wParam)) {
case LBN_SELCHANGE:
ShowRealm(hDlg);
break;
}
return 0;
/* NOTREACHED */
case IDC_REALM_ADD:
AddRealm(hDlg, rgy);
break;
case IDC_REALM_REMOVE:
RemoveRealm(hDlg);
break;
}
break;
case WM_NOTIFY:
switch (((NMHDR *)lParam)->code) {
case PSN_SETACTIVE:
case PSN_RESET:
/* reset button states */
if (((NMHDR *)lParam)->code == PSN_RESET)
SetWindowLong(hDlg, DWL_MSGRESULT, FALSE);
break;
case PSN_APPLY:
/* Save the settings */
SetWindowLong(hDlg, DWL_MSGRESULT, TRUE);
break;
case PSN_KILLACTIVE:
SetWindowLong(hDlg, DWL_MSGRESULT, FALSE);
return 1;
}
break;
}
return FALSE;
}
int WINAPI
WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLn, int nShowCmd)
{
PROPSHEETHEADER psh;
PROPSHEETPAGE psp[1];
int err = 0;
hInstance = hInst;
if ((err = Krb5NdiCreate()) != OK)
return err;
psp[0].dwSize = sizeof(PROPSHEETPAGE);
psp[0].dwFlags = 0;
psp[0].hInstance = hInst;
psp[0].pszTemplate = MAKEINTRESOURCE(IDD_REALMS);
psp[0].pszIcon = NULL;
psp[0].pfnDlgProc = (DLGPROC)Krb5NdiRealmsProc;
psp[0].lParam = (LPARAM)rgy;
psh.dwSize = sizeof(PROPSHEETHEADER);
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
psh.hwndParent = NULL;
psh.hInstance = hInst;
psh.pszIcon = NULL;
psh.pszCaption = (LPTSTR)TEXT("Kerberos v5 Configuration");
psh.pStartPage = 0;
psh.nPages = sizeof(psp)/sizeof(psp[0]);
psh.ppsp = (LPCPROPSHEETPAGE)&psp;
if (PropertySheet(&psh))
Krb5NdiInstall(rgy);
Krb5NdiDestroy(rgy);
return err;
}