summaryrefslogtreecommitdiffstats
path: root/src/windows/kfwlogon/kfwlogon.c
diff options
context:
space:
mode:
authorKen Raeburn <raeburn@mit.edu>2007-06-20 01:19:59 +0000
committerKen Raeburn <raeburn@mit.edu>2007-06-20 01:19:59 +0000
commit78ec90d925e1f672639762e6c9fa674bf7ff0a64 (patch)
tree3aad3df3133e6e0f2922f575b9da94630543f433 /src/windows/kfwlogon/kfwlogon.c
parentd275e06d0cb0f248aa54a6f134a59f84aa563e14 (diff)
downloadkrb5-78ec90d925e1f672639762e6c9fa674bf7ff0a64.tar.gz
krb5-78ec90d925e1f672639762e6c9fa674bf7ff0a64.tar.xz
krb5-78ec90d925e1f672639762e6c9fa674bf7ff0a64.zip
set svn:eol-style to native for *.[ch]
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@19596 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/windows/kfwlogon/kfwlogon.c')
-rw-r--r--src/windows/kfwlogon/kfwlogon.c1268
1 files changed, 634 insertions, 634 deletions
diff --git a/src/windows/kfwlogon/kfwlogon.c b/src/windows/kfwlogon/kfwlogon.c
index 8422f58b11..54d7a5a1d6 100644
--- a/src/windows/kfwlogon/kfwlogon.c
+++ b/src/windows/kfwlogon/kfwlogon.c
@@ -1,634 +1,634 @@
-/*
-Copyright 2005,2006 by the Massachusetts Institute of Technology
-Copyright 2007 by Secure Endpoints Inc.
-
-All rights reserved.
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the name of the Massachusetts
-Institute of Technology (M.I.T.) not be used in advertising or publicity
-pertaining to distribution of the software without specific, written
-prior permission.
-
-M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
-ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
-M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
-ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
-ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
-SOFTWARE.
-
-*/
-
-#include "kfwlogon.h"
-
-#include <io.h>
-#include <stdio.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-
-#include <winsock2.h>
-#include <lm.h>
-#include <nb30.h>
-
-static HANDLE hDLL;
-
-static HANDLE hInitMutex = NULL;
-static BOOL bInit = FALSE;
-
-
-BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
-{
- hDLL = dll;
- switch (reason) {
- case DLL_PROCESS_ATTACH:
- /* Initialization Mutex */
- hInitMutex = CreateMutex(NULL, FALSE, NULL);
- break;
-
- case DLL_PROCESS_DETACH:
- CloseHandle(hInitMutex);
- break;
-
- case DLL_THREAD_ATTACH:
- case DLL_THREAD_DETACH:
- default:
- /* Everything else succeeds but does nothing. */
- break;
- }
-
- return TRUE;
-}
-
-DWORD APIENTRY NPGetCaps(DWORD index)
-{
- switch (index) {
- case WNNC_NET_TYPE:
- /* We aren't a file system; We don't have our own type; use somebody else's. */
- return WNNC_NET_SUN_PC_NFS;
- case WNNC_START:
- /* Say we are already started, even though we might wait after we receive NPLogonNotify */
- return 1;
-
- default:
- return 0;
- }
-}
-
-
-static BOOL
-WINAPI
-UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
-{
- CPINFO CodePageInfo;
-
- GetCPInfo(CP_ACP, &CodePageInfo);
-
- if (CodePageInfo.MaxCharSize > 1)
- // Only supporting non-Unicode strings
- return FALSE;
-
- if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
- {
- // Looks like unicode, better translate it
- // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
- WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
- lpszOutputString, nOutStringLen-1, NULL, NULL);
- lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
- return TRUE;
- }
-
- lpszOutputString[0] = '\0';
- return FALSE;
-} // UnicodeStringToANSI
-
-
-static BOOL
-is_windows_vista(void)
-{
- static BOOL fChecked = FALSE;
- static BOOL fIsWinVista = FALSE;
-
- if (!fChecked)
- {
- OSVERSIONINFO Version;
-
- memset (&Version, 0x00, sizeof(Version));
- Version.dwOSVersionInfoSize = sizeof(Version);
-
- if (GetVersionEx (&Version))
- {
- if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
- Version.dwMajorVersion >= 6)
- fIsWinVista = TRUE;
- }
- fChecked = TRUE;
- }
-
- return fIsWinVista;
-}
-
-
-/* Construct a Logon Script that will cause the LogonEventHandler to be executed
- * under in the logon session
- */
-
-#define RUNDLL32_CMDLINE "rundll32.exe kfwlogon.dll,LogonEventHandler "
-VOID
-ConfigureLogonScript(LPWSTR *lpLogonScript, char * filename) {
- DWORD dwLogonScriptLen;
- LPWSTR lpScript;
- LPSTR lpTemp;
-
- if (!lpLogonScript)
- return;
- *lpLogonScript = NULL;
-
- if (!filename)
- return;
-
- dwLogonScriptLen = strlen(RUNDLL32_CMDLINE) + strlen(filename) + 2;
- lpTemp = (LPSTR) malloc(dwLogonScriptLen);
- if (!lpTemp)
- return;
-
- _snprintf(lpTemp, dwLogonScriptLen, "%s%s", RUNDLL32_CMDLINE, filename);
-
- SetLastError(0);
- dwLogonScriptLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpTemp, -1, NULL, 0);
- DebugEvent("ConfigureLogonScript %s requires %d bytes gle=0x%x", lpTemp, dwLogonScriptLen, GetLastError());
-
- lpScript = LocalAlloc(LMEM_ZEROINIT, dwLogonScriptLen * 2);
- if (lpScript) {
- if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpTemp, -1, lpScript, 2 * dwLogonScriptLen))
- *lpLogonScript = lpScript;
- else {
- DebugEvent("ConfigureLogonScript - MultiByteToWideChar failed gle = 0x%x", GetLastError());
- LocalFree(lpScript);
- }
- } else {
- DebugEvent("LocalAlloc failed gle=0x%x", GetLastError());
- }
- free(lpTemp);
-}
-
-
-DWORD APIENTRY NPLogonNotify(
- PLUID lpLogonId,
- LPCWSTR lpAuthentInfoType,
- LPVOID lpAuthentInfo,
- LPCWSTR lpPreviousAuthentInfoType,
- LPVOID lpPreviousAuthentInfo,
- LPWSTR lpStationName,
- LPVOID StationHandle,
- LPWSTR *lpLogonScript)
-{
- char uname[MAX_USERNAME_LENGTH+1]="";
- char password[MAX_PASSWORD_LENGTH+1]="";
- char logonDomain[MAX_DOMAIN_LENGTH+1]="";
-
- MSV1_0_INTERACTIVE_LOGON *IL;
-
- DWORD code = 0;
-
- char *reason;
- char *ctemp;
-
- BOOLEAN interactive = TRUE;
- HWND hwndOwner = (HWND)StationHandle;
- BOOLEAN lowercased_name = TRUE;
-
- /* Can we load KFW binaries? */
- if ( !KFW_is_available() )
- return 0;
-
- DebugEvent0("NPLogonNotify start");
-
- /* Remote Desktop / Terminal Server connections to existing sessions
- * are interactive logons. Unfortunately, because the session already
- * exists the logon script does not get executed and this prevents
- * us from being able to execute the rundll32 entrypoint
- * LogonEventHandlerA which would process the credential cache this
- * routine will produce. Therefore, we must cleanup orphaned cache
- * files from this routine. We will take care of it before doing
- * anything else.
- */
- KFW_cleanup_orphaned_caches();
-
- /* Are we interactive? */
- if (lpStationName)
- interactive = (wcsicmp(lpStationName, L"WinSta0") == 0);
-
- if ( !interactive ) {
- char station[64]="station";
- DWORD rv;
-
- SetLastError(0);
- rv = WideCharToMultiByte(CP_UTF8, 0, lpStationName, -1,
- station, sizeof(station), NULL, NULL);
- DebugEvent("Skipping NPLogonNotify- LoginId(%d,%d) - Interactive(%d:%s) - gle %d",
- lpLogonId->HighPart, lpLogonId->LowPart, interactive, rv != 0 ? station : "failure", GetLastError());
- return 0;
- } else
- DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart);
-
- /* Initialize Logon Script to none */
- *lpLogonScript=NULL;
-
- /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for
- * our purposes */
-
- if ( wcsicmp(lpAuthentInfoType,L"MSV1_0:Interactive") &&
- wcsicmp(lpAuthentInfoType,L"Kerberos:Interactive") )
- {
- char msg[64];
- WideCharToMultiByte(CP_ACP, 0, lpAuthentInfoType, -1,
- msg, sizeof(msg), NULL, NULL);
- msg[sizeof(msg)-1]='\0';
- DebugEvent("NPLogonNotify - Unsupported Authentication Info Type: %s", msg);
- return 0;
- }
-
- IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
-
- /* Convert from Unicode to ANSI */
-
- /*TODO: Use SecureZeroMemory to erase passwords */
- if (!UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH) ||
- !UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH) ||
- !UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH))
- return 0;
-
- /* Make sure AD-DOMAINS sent from login that is sent to us is stripped */
- ctemp = strchr(uname, '@');
- if (ctemp) *ctemp = 0;
-
- /* is the name all lowercase? */
- for ( ctemp = uname; *ctemp ; ctemp++) {
- if ( !islower(*ctemp) ) {
- lowercased_name = FALSE;
- break;
- }
- }
-
- code = KFW_get_cred(uname, password, 0, &reason);
- DebugEvent("NPLogonNotify - KFW_get_cred uname=[%s] code=[%d]",uname, code);
-
- /* remove any kerberos 5 tickets currently held by the SYSTEM account
- * for this user
- */
- if (!code) {
- char filename[MAX_PATH+1] = "";
- char acctname[MAX_USERNAME_LENGTH+MAX_DOMAIN_LENGTH+3]="";
- PSID pUserSid = NULL;
- LPTSTR pReferencedDomainName = NULL;
- DWORD dwSidLen = 0, dwDomainLen = 0, count;
- SID_NAME_USE eUse;
-
- if (_snprintf(acctname, sizeof(acctname), "%s\\%s", logonDomain, uname) < 0) {
- code = -1;
- goto cleanup;
- }
-
- count = GetTempPath(sizeof(filename), filename);
- if (count == 0 || count > (sizeof(filename)-1)) {
- code = -1;
- goto cleanup;
- }
-
- if (_snprintf(filename, sizeof(filename), "%s\\kfwlogon-%x.%x",
- filename, lpLogonId->HighPart, lpLogonId->LowPart) < 0)
- {
- code = -1;
- goto cleanup;
- }
-
- KFW_copy_cache_to_system_file(uname, filename);
-
- /* Need to determine the SID */
-
- /* First get the size of the required buffers */
- LookupAccountName (NULL,
- acctname,
- pUserSid,
- &dwSidLen,
- pReferencedDomainName,
- &dwDomainLen,
- &eUse);
- if(dwSidLen){
- pUserSid = (PSID) malloc (dwSidLen);
- memset(pUserSid,0,dwSidLen);
- }
-
- if(dwDomainLen){
- pReferencedDomainName = (LPTSTR) malloc (dwDomainLen * sizeof(TCHAR));
- memset(pReferencedDomainName,0,dwDomainLen * sizeof(TCHAR));
- }
-
- //Now get the SID and the domain name
- if (pUserSid && LookupAccountName( NULL,
- acctname,
- pUserSid,
- &dwSidLen,
- pReferencedDomainName,
- &dwDomainLen,
- &eUse))
- {
- DebugEvent("LookupAccountName obtained user %s sid in domain %s", acctname, pReferencedDomainName);
- code = KFW_set_ccache_dacl_with_user_sid(filename, pUserSid);
-
-#ifdef USE_WINLOGON_EVENT
- /* If we are on Vista, setup a LogonScript
- * that will execute the LogonEventHandler entry point via rundll32.exe
- */
- if (is_windows_vista()) {
- ConfigureLogonScript(lpLogonScript, filename);
- if (*lpLogonScript)
- DebugEvent0("LogonScript assigned");
- else
- DebugEvent0("No Logon Script");
- }
-#else
- ConfigureLogonScript(lpLogonScript, filename);
- if (*lpLogonScript)
- DebugEvent0("LogonScript assigned");
- else
- DebugEvent0("No Logon Script");
-#endif
- } else {
- DebugEvent0("LookupAccountName failed");
- DeleteFile(filename);
- code = -1;
- }
-
- cleanup:
- if (pUserSid)
- free(pUserSid);
- if (pReferencedDomainName)
- free(pReferencedDomainName);
- }
-
- KFW_destroy_tickets_for_principal(uname);
-
- if (code) {
- char msg[128];
- HANDLE h;
- char *ptbuf[1];
-
- StringCbPrintf(msg, sizeof(msg), "Kerberos ticket acquisition failed: %s", reason);
-
- h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME);
- ptbuf[0] = msg;
- ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL, 1, 0, ptbuf, NULL);
- DeregisterEventSource(h);
- SetLastError(code);
- }
-
- if (code)
- DebugEvent0("NPLogonNotify failure");
- else
- DebugEvent0("NPLogonNotify success");
-
- return code;
-}
-
-
-DWORD APIENTRY NPPasswordChangeNotify(
- LPCWSTR lpAuthentInfoType,
- LPVOID lpAuthentInfo,
- LPCWSTR lpPreviousAuthentInfoType,
- LPVOID lpPreviousAuthentInfo,
- LPWSTR lpStationName,
- LPVOID StationHandle,
- DWORD dwChangeInfo)
-{
- return 0;
-}
-
-#include <userenv.h>
-#include <Winwlx.h>
-
-#ifdef COMMENT
-typedef struct _WLX_NOTIFICATION_INFO {
- ULONG Size;
- ULONG Flags;
- PWSTR UserName;
- PWSTR Domain;
- PWSTR WindowStation;
- HANDLE hToken;
- HDESK hDesktop;
- PFNMSGECALLBACK pStatusCallback;
-} WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
-#endif
-
-VOID KFW_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
-{
- DebugEvent0("KFW_Startup_Event");
-}
-
-static BOOL
-GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
-{
- NTSTATUS Status = 0;
-#if 0
- HANDLE TokenHandle;
-#endif
- TOKEN_STATISTICS Stats;
- DWORD ReqLen;
- BOOL Success;
-
- if (!ppSessionData)
- return FALSE;
- *ppSessionData = NULL;
-
-#if 0
- Success = OpenProcessToken( HANDLE GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
- if ( !Success )
- return FALSE;
-#endif
-
- Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
-#if 0
- CloseHandle( TokenHandle );
-#endif
- if ( !Success )
- return FALSE;
-
- Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
- if ( FAILED(Status) || !ppSessionData )
- return FALSE;
-
- return TRUE;
-}
-
-VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
-{
-#ifdef USE_WINLOGON_EVENT
- WCHAR szUserW[128] = L"";
- char szUserA[128] = "";
- char szPath[MAX_PATH] = "";
- char szLogonId[128] = "";
- DWORD count;
- char filename[MAX_PATH] = "";
- char newfilename[MAX_PATH] = "";
- char commandline[MAX_PATH+256] = "";
- STARTUPINFO startupinfo;
- PROCESS_INFORMATION procinfo;
- HANDLE hf = NULL;
-
- LUID LogonId = {0, 0};
- PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
-
- HKEY hKey1 = NULL, hKey2 = NULL;
-
- DebugEvent0("KFW_Logon_Event - Start");
-
- GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
-
- if ( pLogonSessionData ) {
- LogonId = pLogonSessionData->LogonId;
- DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
-
- _snprintf(szLogonId, sizeof(szLogonId), "kfwlogon-%d.%d",LogonId.HighPart, LogonId.LowPart);
- LsaFreeReturnBuffer( pLogonSessionData );
- } else {
- DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
- return;
- }
-
- count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
- if ( count > sizeof(filename) || count == 0 ) {
- GetWindowsDirectory(filename, sizeof(filename));
- }
-
- if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) {
- DebugEvent0("KFW_Logon_Event - filename too long");
- return;
- }
-
- strcat(filename, "\\");
- strcat(filename, szLogonId);
-
- hf = CreateFile(filename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL);
- if (hf == INVALID_HANDLE_VALUE) {
- DebugEvent0("KFW_Logon_Event - file cannot be opened");
- return;
- }
- CloseHandle(hf);
-
- if (KFW_set_ccache_dacl(filename, pInfo->hToken)) {
- DebugEvent0("KFW_Logon_Event - unable to set dacl");
- DeleteFile(filename);
- return;
- }
-
- if (KFW_obtain_user_temp_directory(pInfo->hToken, newfilename, sizeof(newfilename))) {
- DebugEvent0("KFW_Logon_Event - unable to obtain temp directory");
- return;
- }
-
- if ( strlen(newfilename) + strlen(szLogonId) + 2 > sizeof(newfilename) ) {
- DebugEvent0("KFW_Logon_Event - new filename too long");
- return;
- }
-
- strcat(newfilename, "\\");
- strcat(newfilename, szLogonId);
-
- if (!MoveFileEx(filename, newfilename,
- MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
- DebugEvent("KFW_Logon_Event - MoveFileEx failed GLE = 0x%x", GetLastError());
- return;
- }
-
- _snprintf(commandline, sizeof(commandline), "kfwcpcc.exe \"%s\"", newfilename);
-
- GetStartupInfo(&startupinfo);
- if (CreateProcessAsUser( pInfo->hToken,
- "kfwcpcc.exe",
- commandline,
- NULL,
- NULL,
- FALSE,
- CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
- NULL,
- NULL,
- &startupinfo,
- &procinfo))
- {
- DebugEvent("KFW_Logon_Event - CommandLine %s", commandline);
-
- WaitForSingleObject(procinfo.hProcess, 30000);
-
- CloseHandle(procinfo.hThread);
- CloseHandle(procinfo.hProcess);
- } else {
- DebugEvent0("KFW_Logon_Event - CreateProcessFailed");
- }
-
- DeleteFile(newfilename);
-
- DebugEvent0("KFW_Logon_Event - End");
-#endif /* USE_WINLOGON_EVENT */
-}
-
-
-/* Documentation on the use of RunDll32 entrypoints can be found
- * at http://support.microsoft.com/kb/164787
- */
-void CALLBACK
-LogonEventHandlerA(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
-{
- HANDLE hf = NULL;
- char commandline[MAX_PATH+256] = "";
- STARTUPINFO startupinfo;
- PROCESS_INFORMATION procinfo;
-
- DebugEvent0("LogonEventHandler - Start");
-
- /* Validate lpszCmdLine as a file */
- hf = CreateFile(lpszCmdLine, GENERIC_READ | DELETE, 0, NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL);
- if (hf == INVALID_HANDLE_VALUE) {
- DebugEvent("LogonEventHandler - \"%s\" cannot be opened", lpszCmdLine);
- return;
- }
- CloseHandle(hf);
-
-
- _snprintf(commandline, sizeof(commandline), "kfwcpcc.exe \"%s\"", lpszCmdLine);
-
- GetStartupInfo(&startupinfo);
- SetLastError(0);
- if (CreateProcess( NULL,
- commandline,
- NULL,
- NULL,
- FALSE,
- CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
- NULL,
- NULL,
- &startupinfo,
- &procinfo))
- {
- DebugEvent("KFW_Logon_Event - CommandLine %s", commandline);
-
- WaitForSingleObject(procinfo.hProcess, 30000);
-
- CloseHandle(procinfo.hThread);
- CloseHandle(procinfo.hProcess);
- } else {
- DebugEvent("KFW_Logon_Event - CreateProcessFailed \"%s\" GLE 0x%x",
- commandline, GetLastError());
- DebugEvent("KFW_Logon_Event PATH %s", getenv("PATH"));
- }
-
- DeleteFile(lpszCmdLine);
-
- DebugEvent0("KFW_Logon_Event - End");
-}
+/*
+Copyright 2005,2006 by the Massachusetts Institute of Technology
+Copyright 2007 by Secure Endpoints Inc.
+
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of the Massachusetts
+Institute of Technology (M.I.T.) not be used in advertising or publicity
+pertaining to distribution of the software without specific, written
+prior permission.
+
+M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+*/
+
+#include "kfwlogon.h"
+
+#include <io.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include <winsock2.h>
+#include <lm.h>
+#include <nb30.h>
+
+static HANDLE hDLL;
+
+static HANDLE hInitMutex = NULL;
+static BOOL bInit = FALSE;
+
+
+BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
+{
+ hDLL = dll;
+ switch (reason) {
+ case DLL_PROCESS_ATTACH:
+ /* Initialization Mutex */
+ hInitMutex = CreateMutex(NULL, FALSE, NULL);
+ break;
+
+ case DLL_PROCESS_DETACH:
+ CloseHandle(hInitMutex);
+ break;
+
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ default:
+ /* Everything else succeeds but does nothing. */
+ break;
+ }
+
+ return TRUE;
+}
+
+DWORD APIENTRY NPGetCaps(DWORD index)
+{
+ switch (index) {
+ case WNNC_NET_TYPE:
+ /* We aren't a file system; We don't have our own type; use somebody else's. */
+ return WNNC_NET_SUN_PC_NFS;
+ case WNNC_START:
+ /* Say we are already started, even though we might wait after we receive NPLogonNotify */
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+
+static BOOL
+WINAPI
+UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
+{
+ CPINFO CodePageInfo;
+
+ GetCPInfo(CP_ACP, &CodePageInfo);
+
+ if (CodePageInfo.MaxCharSize > 1)
+ // Only supporting non-Unicode strings
+ return FALSE;
+
+ if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
+ {
+ // Looks like unicode, better translate it
+ // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
+ WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
+ lpszOutputString, nOutStringLen-1, NULL, NULL);
+ lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
+ return TRUE;
+ }
+
+ lpszOutputString[0] = '\0';
+ return FALSE;
+} // UnicodeStringToANSI
+
+
+static BOOL
+is_windows_vista(void)
+{
+ static BOOL fChecked = FALSE;
+ static BOOL fIsWinVista = FALSE;
+
+ if (!fChecked)
+ {
+ OSVERSIONINFO Version;
+
+ memset (&Version, 0x00, sizeof(Version));
+ Version.dwOSVersionInfoSize = sizeof(Version);
+
+ if (GetVersionEx (&Version))
+ {
+ if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT &&
+ Version.dwMajorVersion >= 6)
+ fIsWinVista = TRUE;
+ }
+ fChecked = TRUE;
+ }
+
+ return fIsWinVista;
+}
+
+
+/* Construct a Logon Script that will cause the LogonEventHandler to be executed
+ * under in the logon session
+ */
+
+#define RUNDLL32_CMDLINE "rundll32.exe kfwlogon.dll,LogonEventHandler "
+VOID
+ConfigureLogonScript(LPWSTR *lpLogonScript, char * filename) {
+ DWORD dwLogonScriptLen;
+ LPWSTR lpScript;
+ LPSTR lpTemp;
+
+ if (!lpLogonScript)
+ return;
+ *lpLogonScript = NULL;
+
+ if (!filename)
+ return;
+
+ dwLogonScriptLen = strlen(RUNDLL32_CMDLINE) + strlen(filename) + 2;
+ lpTemp = (LPSTR) malloc(dwLogonScriptLen);
+ if (!lpTemp)
+ return;
+
+ _snprintf(lpTemp, dwLogonScriptLen, "%s%s", RUNDLL32_CMDLINE, filename);
+
+ SetLastError(0);
+ dwLogonScriptLen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpTemp, -1, NULL, 0);
+ DebugEvent("ConfigureLogonScript %s requires %d bytes gle=0x%x", lpTemp, dwLogonScriptLen, GetLastError());
+
+ lpScript = LocalAlloc(LMEM_ZEROINIT, dwLogonScriptLen * 2);
+ if (lpScript) {
+ if (MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, lpTemp, -1, lpScript, 2 * dwLogonScriptLen))
+ *lpLogonScript = lpScript;
+ else {
+ DebugEvent("ConfigureLogonScript - MultiByteToWideChar failed gle = 0x%x", GetLastError());
+ LocalFree(lpScript);
+ }
+ } else {
+ DebugEvent("LocalAlloc failed gle=0x%x", GetLastError());
+ }
+ free(lpTemp);
+}
+
+
+DWORD APIENTRY NPLogonNotify(
+ PLUID lpLogonId,
+ LPCWSTR lpAuthentInfoType,
+ LPVOID lpAuthentInfo,
+ LPCWSTR lpPreviousAuthentInfoType,
+ LPVOID lpPreviousAuthentInfo,
+ LPWSTR lpStationName,
+ LPVOID StationHandle,
+ LPWSTR *lpLogonScript)
+{
+ char uname[MAX_USERNAME_LENGTH+1]="";
+ char password[MAX_PASSWORD_LENGTH+1]="";
+ char logonDomain[MAX_DOMAIN_LENGTH+1]="";
+
+ MSV1_0_INTERACTIVE_LOGON *IL;
+
+ DWORD code = 0;
+
+ char *reason;
+ char *ctemp;
+
+ BOOLEAN interactive = TRUE;
+ HWND hwndOwner = (HWND)StationHandle;
+ BOOLEAN lowercased_name = TRUE;
+
+ /* Can we load KFW binaries? */
+ if ( !KFW_is_available() )
+ return 0;
+
+ DebugEvent0("NPLogonNotify start");
+
+ /* Remote Desktop / Terminal Server connections to existing sessions
+ * are interactive logons. Unfortunately, because the session already
+ * exists the logon script does not get executed and this prevents
+ * us from being able to execute the rundll32 entrypoint
+ * LogonEventHandlerA which would process the credential cache this
+ * routine will produce. Therefore, we must cleanup orphaned cache
+ * files from this routine. We will take care of it before doing
+ * anything else.
+ */
+ KFW_cleanup_orphaned_caches();
+
+ /* Are we interactive? */
+ if (lpStationName)
+ interactive = (wcsicmp(lpStationName, L"WinSta0") == 0);
+
+ if ( !interactive ) {
+ char station[64]="station";
+ DWORD rv;
+
+ SetLastError(0);
+ rv = WideCharToMultiByte(CP_UTF8, 0, lpStationName, -1,
+ station, sizeof(station), NULL, NULL);
+ DebugEvent("Skipping NPLogonNotify- LoginId(%d,%d) - Interactive(%d:%s) - gle %d",
+ lpLogonId->HighPart, lpLogonId->LowPart, interactive, rv != 0 ? station : "failure", GetLastError());
+ return 0;
+ } else
+ DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart);
+
+ /* Initialize Logon Script to none */
+ *lpLogonScript=NULL;
+
+ /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for
+ * our purposes */
+
+ if ( wcsicmp(lpAuthentInfoType,L"MSV1_0:Interactive") &&
+ wcsicmp(lpAuthentInfoType,L"Kerberos:Interactive") )
+ {
+ char msg[64];
+ WideCharToMultiByte(CP_ACP, 0, lpAuthentInfoType, -1,
+ msg, sizeof(msg), NULL, NULL);
+ msg[sizeof(msg)-1]='\0';
+ DebugEvent("NPLogonNotify - Unsupported Authentication Info Type: %s", msg);
+ return 0;
+ }
+
+ IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
+
+ /* Convert from Unicode to ANSI */
+
+ /*TODO: Use SecureZeroMemory to erase passwords */
+ if (!UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH) ||
+ !UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH) ||
+ !UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH))
+ return 0;
+
+ /* Make sure AD-DOMAINS sent from login that is sent to us is stripped */
+ ctemp = strchr(uname, '@');
+ if (ctemp) *ctemp = 0;
+
+ /* is the name all lowercase? */
+ for ( ctemp = uname; *ctemp ; ctemp++) {
+ if ( !islower(*ctemp) ) {
+ lowercased_name = FALSE;
+ break;
+ }
+ }
+
+ code = KFW_get_cred(uname, password, 0, &reason);
+ DebugEvent("NPLogonNotify - KFW_get_cred uname=[%s] code=[%d]",uname, code);
+
+ /* remove any kerberos 5 tickets currently held by the SYSTEM account
+ * for this user
+ */
+ if (!code) {
+ char filename[MAX_PATH+1] = "";
+ char acctname[MAX_USERNAME_LENGTH+MAX_DOMAIN_LENGTH+3]="";
+ PSID pUserSid = NULL;
+ LPTSTR pReferencedDomainName = NULL;
+ DWORD dwSidLen = 0, dwDomainLen = 0, count;
+ SID_NAME_USE eUse;
+
+ if (_snprintf(acctname, sizeof(acctname), "%s\\%s", logonDomain, uname) < 0) {
+ code = -1;
+ goto cleanup;
+ }
+
+ count = GetTempPath(sizeof(filename), filename);
+ if (count == 0 || count > (sizeof(filename)-1)) {
+ code = -1;
+ goto cleanup;
+ }
+
+ if (_snprintf(filename, sizeof(filename), "%s\\kfwlogon-%x.%x",
+ filename, lpLogonId->HighPart, lpLogonId->LowPart) < 0)
+ {
+ code = -1;
+ goto cleanup;
+ }
+
+ KFW_copy_cache_to_system_file(uname, filename);
+
+ /* Need to determine the SID */
+
+ /* First get the size of the required buffers */
+ LookupAccountName (NULL,
+ acctname,
+ pUserSid,
+ &dwSidLen,
+ pReferencedDomainName,
+ &dwDomainLen,
+ &eUse);
+ if(dwSidLen){
+ pUserSid = (PSID) malloc (dwSidLen);
+ memset(pUserSid,0,dwSidLen);
+ }
+
+ if(dwDomainLen){
+ pReferencedDomainName = (LPTSTR) malloc (dwDomainLen * sizeof(TCHAR));
+ memset(pReferencedDomainName,0,dwDomainLen * sizeof(TCHAR));
+ }
+
+ //Now get the SID and the domain name
+ if (pUserSid && LookupAccountName( NULL,
+ acctname,
+ pUserSid,
+ &dwSidLen,
+ pReferencedDomainName,
+ &dwDomainLen,
+ &eUse))
+ {
+ DebugEvent("LookupAccountName obtained user %s sid in domain %s", acctname, pReferencedDomainName);
+ code = KFW_set_ccache_dacl_with_user_sid(filename, pUserSid);
+
+#ifdef USE_WINLOGON_EVENT
+ /* If we are on Vista, setup a LogonScript
+ * that will execute the LogonEventHandler entry point via rundll32.exe
+ */
+ if (is_windows_vista()) {
+ ConfigureLogonScript(lpLogonScript, filename);
+ if (*lpLogonScript)
+ DebugEvent0("LogonScript assigned");
+ else
+ DebugEvent0("No Logon Script");
+ }
+#else
+ ConfigureLogonScript(lpLogonScript, filename);
+ if (*lpLogonScript)
+ DebugEvent0("LogonScript assigned");
+ else
+ DebugEvent0("No Logon Script");
+#endif
+ } else {
+ DebugEvent0("LookupAccountName failed");
+ DeleteFile(filename);
+ code = -1;
+ }
+
+ cleanup:
+ if (pUserSid)
+ free(pUserSid);
+ if (pReferencedDomainName)
+ free(pReferencedDomainName);
+ }
+
+ KFW_destroy_tickets_for_principal(uname);
+
+ if (code) {
+ char msg[128];
+ HANDLE h;
+ char *ptbuf[1];
+
+ StringCbPrintf(msg, sizeof(msg), "Kerberos ticket acquisition failed: %s", reason);
+
+ h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME);
+ ptbuf[0] = msg;
+ ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL, 1, 0, ptbuf, NULL);
+ DeregisterEventSource(h);
+ SetLastError(code);
+ }
+
+ if (code)
+ DebugEvent0("NPLogonNotify failure");
+ else
+ DebugEvent0("NPLogonNotify success");
+
+ return code;
+}
+
+
+DWORD APIENTRY NPPasswordChangeNotify(
+ LPCWSTR lpAuthentInfoType,
+ LPVOID lpAuthentInfo,
+ LPCWSTR lpPreviousAuthentInfoType,
+ LPVOID lpPreviousAuthentInfo,
+ LPWSTR lpStationName,
+ LPVOID StationHandle,
+ DWORD dwChangeInfo)
+{
+ return 0;
+}
+
+#include <userenv.h>
+#include <Winwlx.h>
+
+#ifdef COMMENT
+typedef struct _WLX_NOTIFICATION_INFO {
+ ULONG Size;
+ ULONG Flags;
+ PWSTR UserName;
+ PWSTR Domain;
+ PWSTR WindowStation;
+ HANDLE hToken;
+ HDESK hDesktop;
+ PFNMSGECALLBACK pStatusCallback;
+} WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
+#endif
+
+VOID KFW_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
+{
+ DebugEvent0("KFW_Startup_Event");
+}
+
+static BOOL
+GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
+{
+ NTSTATUS Status = 0;
+#if 0
+ HANDLE TokenHandle;
+#endif
+ TOKEN_STATISTICS Stats;
+ DWORD ReqLen;
+ BOOL Success;
+
+ if (!ppSessionData)
+ return FALSE;
+ *ppSessionData = NULL;
+
+#if 0
+ Success = OpenProcessToken( HANDLE GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
+ if ( !Success )
+ return FALSE;
+#endif
+
+ Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
+#if 0
+ CloseHandle( TokenHandle );
+#endif
+ if ( !Success )
+ return FALSE;
+
+ Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
+ if ( FAILED(Status) || !ppSessionData )
+ return FALSE;
+
+ return TRUE;
+}
+
+VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
+{
+#ifdef USE_WINLOGON_EVENT
+ WCHAR szUserW[128] = L"";
+ char szUserA[128] = "";
+ char szPath[MAX_PATH] = "";
+ char szLogonId[128] = "";
+ DWORD count;
+ char filename[MAX_PATH] = "";
+ char newfilename[MAX_PATH] = "";
+ char commandline[MAX_PATH+256] = "";
+ STARTUPINFO startupinfo;
+ PROCESS_INFORMATION procinfo;
+ HANDLE hf = NULL;
+
+ LUID LogonId = {0, 0};
+ PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
+
+ HKEY hKey1 = NULL, hKey2 = NULL;
+
+ DebugEvent0("KFW_Logon_Event - Start");
+
+ GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
+
+ if ( pLogonSessionData ) {
+ LogonId = pLogonSessionData->LogonId;
+ DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
+
+ _snprintf(szLogonId, sizeof(szLogonId), "kfwlogon-%d.%d",LogonId.HighPart, LogonId.LowPart);
+ LsaFreeReturnBuffer( pLogonSessionData );
+ } else {
+ DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
+ return;
+ }
+
+ count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
+ if ( count > sizeof(filename) || count == 0 ) {
+ GetWindowsDirectory(filename, sizeof(filename));
+ }
+
+ if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) {
+ DebugEvent0("KFW_Logon_Event - filename too long");
+ return;
+ }
+
+ strcat(filename, "\\");
+ strcat(filename, szLogonId);
+
+ hf = CreateFile(filename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hf == INVALID_HANDLE_VALUE) {
+ DebugEvent0("KFW_Logon_Event - file cannot be opened");
+ return;
+ }
+ CloseHandle(hf);
+
+ if (KFW_set_ccache_dacl(filename, pInfo->hToken)) {
+ DebugEvent0("KFW_Logon_Event - unable to set dacl");
+ DeleteFile(filename);
+ return;
+ }
+
+ if (KFW_obtain_user_temp_directory(pInfo->hToken, newfilename, sizeof(newfilename))) {
+ DebugEvent0("KFW_Logon_Event - unable to obtain temp directory");
+ return;
+ }
+
+ if ( strlen(newfilename) + strlen(szLogonId) + 2 > sizeof(newfilename) ) {
+ DebugEvent0("KFW_Logon_Event - new filename too long");
+ return;
+ }
+
+ strcat(newfilename, "\\");
+ strcat(newfilename, szLogonId);
+
+ if (!MoveFileEx(filename, newfilename,
+ MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
+ DebugEvent("KFW_Logon_Event - MoveFileEx failed GLE = 0x%x", GetLastError());
+ return;
+ }
+
+ _snprintf(commandline, sizeof(commandline), "kfwcpcc.exe \"%s\"", newfilename);
+
+ GetStartupInfo(&startupinfo);
+ if (CreateProcessAsUser( pInfo->hToken,
+ "kfwcpcc.exe",
+ commandline,
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
+ NULL,
+ NULL,
+ &startupinfo,
+ &procinfo))
+ {
+ DebugEvent("KFW_Logon_Event - CommandLine %s", commandline);
+
+ WaitForSingleObject(procinfo.hProcess, 30000);
+
+ CloseHandle(procinfo.hThread);
+ CloseHandle(procinfo.hProcess);
+ } else {
+ DebugEvent0("KFW_Logon_Event - CreateProcessFailed");
+ }
+
+ DeleteFile(newfilename);
+
+ DebugEvent0("KFW_Logon_Event - End");
+#endif /* USE_WINLOGON_EVENT */
+}
+
+
+/* Documentation on the use of RunDll32 entrypoints can be found
+ * at http://support.microsoft.com/kb/164787
+ */
+void CALLBACK
+LogonEventHandlerA(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
+{
+ HANDLE hf = NULL;
+ char commandline[MAX_PATH+256] = "";
+ STARTUPINFO startupinfo;
+ PROCESS_INFORMATION procinfo;
+
+ DebugEvent0("LogonEventHandler - Start");
+
+ /* Validate lpszCmdLine as a file */
+ hf = CreateFile(lpszCmdLine, GENERIC_READ | DELETE, 0, NULL, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hf == INVALID_HANDLE_VALUE) {
+ DebugEvent("LogonEventHandler - \"%s\" cannot be opened", lpszCmdLine);
+ return;
+ }
+ CloseHandle(hf);
+
+
+ _snprintf(commandline, sizeof(commandline), "kfwcpcc.exe \"%s\"", lpszCmdLine);
+
+ GetStartupInfo(&startupinfo);
+ SetLastError(0);
+ if (CreateProcess( NULL,
+ commandline,
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
+ NULL,
+ NULL,
+ &startupinfo,
+ &procinfo))
+ {
+ DebugEvent("KFW_Logon_Event - CommandLine %s", commandline);
+
+ WaitForSingleObject(procinfo.hProcess, 30000);
+
+ CloseHandle(procinfo.hThread);
+ CloseHandle(procinfo.hProcess);
+ } else {
+ DebugEvent("KFW_Logon_Event - CreateProcessFailed \"%s\" GLE 0x%x",
+ commandline, GetLastError());
+ DebugEvent("KFW_Logon_Event PATH %s", getenv("PATH"));
+ }
+
+ DeleteFile(lpszCmdLine);
+
+ DebugEvent0("KFW_Logon_Event - End");
+}