/* * Registry keys for compat: * HKLM\System\CurrentControlSet\Control\Lsa\Kerberos\Domains * Keys: * * 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: * : * Specific principal to this local user * : * All users in this domain to this 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 #include #include #include #include #include #include #define ERR_NDI_LOW_MEM ERROR_NOT_ENOUGH_MEMORY #define OK ERROR_SUCCESS #include //#include #include #define SECURITY_WIN32 #include //#include #include #include #include #include #include #include #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; }