From e3aa436cc8b1eab7ef67f15ec17aa4bf8310dca7 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Mon, 24 Jul 2006 06:58:23 +0000 Subject: Windows Integrated Login Fixes for KFW 3.1 KFW integrated login was failing when the user is not a power user or administrator. This was occurring because the temporary file ccache was being created in a directory the user could not read. While fixing this it was noticed that the ACLs on the ccache were too broad. Instead of applying a fix to the FILE: krb5_ccache implementation it was decided that simply applying a new set of ACLs (SYSTEM and "user" with no inheritance) to the file immediately after the krb5_cc_initialize() call would close the broadest security issues. The file is initially created in the SYSTEM %TEMP% directory with "SYSTEM" ACL only. Then it is moved to the user's %TEMP% directory with "SYSTEM" and "user" ACLs. Finally, after copying the credentials to the API: ccache, the file is deleted. ticket: new tags: pullup component: windows git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@18379 dc483132-0cff-0310-8789-dd5450dbe970 --- src/windows/kfwlogon/Makefile.in | 74 +++++++++++----------- src/windows/kfwlogon/kfwcommon.c | 131 +++++++++++++++++++++++++++++++++++++-- src/windows/kfwlogon/kfwcpcc.c | 2 +- src/windows/kfwlogon/kfwlogon.c | 50 +++++++++++---- src/windows/kfwlogon/kfwlogon.h | 4 +- 5 files changed, 206 insertions(+), 55 deletions(-) (limited to 'src/windows/kfwlogon') diff --git a/src/windows/kfwlogon/Makefile.in b/src/windows/kfwlogon/Makefile.in index 0b3879c591..03fc6e7e4c 100644 --- a/src/windows/kfwlogon/Makefile.in +++ b/src/windows/kfwlogon/Makefile.in @@ -1,37 +1,37 @@ -# Makefile for the KFW Network Provider -# - -thisconfigdir=./.. -myfulldir=windows/nplogon -mydir=. -BUILDTOP=$(REL)..$(S).. -DEFINES = -LOCALINCLUDES = -I$(BUILDTOP) -I$(PISMERE)\athena\util\loadfuncs \ - -I$(PISMERE)\athena\auth\krb5\src\include\kerberosIV \ - -I$(PISMERE)\athena\auth\krb4\include \ - -I$(PISMERE)\athena\auth\leash\include -PROG_LIBPATH=-L$(TOPLIBD) -L$(KRB5_LIBDIR) - -SYSLIBS = kernel32.lib user32.lib advapi32.lib wsock32.lib secur32.lib -RFLAGS = $(LOCALINCLUDES) -RCFLAGS = $(RFLAGS) -D_WIN32 - -all-windows:: $(OUTPRE)kfwlogon.dll $(OUTPRE)kfwcpcc.exe - -$(OUTPRE)kfwlogon.res: kfwlogon.rc ..\version.rc - -$(OUTPRE)kfwcpcc.res: kfwcpcc.rc ..\version.rc - -$(OUTPRE)kfwlogon.dll: $(OUTPRE)kfwlogon.obj $(OUTPRE)kfwcommon.obj $(OUTPRE)kfwlogon.res - link $(DLL_LINKOPTS) -out:$@ $(OUTPRE)kfwlogon.obj $(OUTPRE)kfwcommon.obj -entry:DllEntryPoint -def:kfwlogon.def $(SYSLIBS) $(KLIB) $(CLIB) $(SCLIB) - -$(OUTPRE)kfwcpcc.exe: $(OUTPRE)kfwcpcc.obj $(OUTPRE)kfwcommon.obj $(OUTPRE)kfwcpcc.res - link $(EXE_LINKOPTS) -out:$@ $(OUTPRE)kfwcpcc.obj $(OUTPRE)kfwcommon.obj $(SYSLIBS) $(KLIB) $(CLIB) $(SCLIB) - -install:: - copy $(OUTPRE)kfwlogon.dll $(DESTDIR) - copy $(OUTPRE)kfwcpcc.exe $(DESTDIR) - -clean:: - $(RM) $(OUTPRE)*.exe $(OUTPRE)*.dll $(OUTPRE)*.res - +# Makefile for the KFW Network Provider +# + +thisconfigdir=./.. +myfulldir=windows/nplogon +mydir=. +BUILDTOP=$(REL)..$(S).. +DEFINES = +LOCALINCLUDES = -I$(BUILDTOP) -I$(PISMERE)\athena\util\loadfuncs \ + -I$(PISMERE)\athena\auth\krb5\src\include\kerberosIV \ + -I$(PISMERE)\athena\auth\krb4\include \ + -I$(PISMERE)\athena\auth\leash\include +PROG_LIBPATH=-L$(TOPLIBD) -L$(KRB5_LIBDIR) + +SYSLIBS = kernel32.lib user32.lib advapi32.lib wsock32.lib secur32.lib userenv.lib +RFLAGS = $(LOCALINCLUDES) +RCFLAGS = $(RFLAGS) -D_WIN32 + +all-windows:: $(OUTPRE)kfwlogon.dll $(OUTPRE)kfwcpcc.exe + +$(OUTPRE)kfwlogon.res: kfwlogon.rc ..\version.rc + +$(OUTPRE)kfwcpcc.res: kfwcpcc.rc ..\version.rc + +$(OUTPRE)kfwlogon.dll: $(OUTPRE)kfwlogon.obj $(OUTPRE)kfwcommon.obj $(OUTPRE)kfwlogon.res + link $(DLL_LINKOPTS) -out:$@ $(OUTPRE)kfwlogon.obj $(OUTPRE)kfwcommon.obj -entry:DllEntryPoint -def:kfwlogon.def $(SYSLIBS) $(KLIB) $(CLIB) + +$(OUTPRE)kfwcpcc.exe: $(OUTPRE)kfwcpcc.obj $(OUTPRE)kfwcommon.obj $(OUTPRE)kfwcpcc.res + link $(EXE_LINKOPTS) -out:$@ $(OUTPRE)kfwcpcc.obj $(OUTPRE)kfwcommon.obj $(SYSLIBS) $(KLIB) $(CLIB) + +install:: + copy $(OUTPRE)kfwlogon.dll $(DESTDIR) + copy $(OUTPRE)kfwcpcc.exe $(DESTDIR) + +clean:: + $(RM) $(OUTPRE)*.exe $(OUTPRE)*.dll $(OUTPRE)*.res + diff --git a/src/windows/kfwlogon/kfwcommon.c b/src/windows/kfwlogon/kfwcommon.c index 251e1436b7..a4263c8382 100644 --- a/src/windows/kfwlogon/kfwcommon.c +++ b/src/windows/kfwlogon/kfwcommon.c @@ -24,6 +24,9 @@ SOFTWARE. #include "kfwlogon.h" #include +#include +#include +#include #include #include @@ -758,6 +761,107 @@ KFW_get_cred( char * username, return(code); } +int KFW_set_ccache_dacl(char *filename, HANDLE hUserToken) +{ + // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY; + PSID pSystemSID = NULL; + DWORD SystemSIDlength, UserSIDlength; + PACL ccacheACL = NULL; + DWORD ccacheACLlength; + PTOKEN_USER pTokenUser = NULL; + DWORD retLen; + int ret = 0; + + /* Get System SID */ + ConvertStringSidToSid(SDDL_LOCAL_SYSTEM, &pSystemSID); + + /* Create ACL */ + SystemSIDlength = GetLengthSid(pSystemSID); + ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + + SystemSIDlength - sizeof(DWORD); + + if (hUserToken) { + if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen)) + { + if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) { + pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen); + + if (!GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen)) + { + DebugEvent("GetTokenInformation failed: GLE = %lX", GetLastError()); + } + } + } + + if (pTokenUser) { + UserSIDlength = GetLengthSid(pTokenUser->User.Sid); + + ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength + - sizeof(DWORD); + } + } + + ccacheACL = GlobalAlloc(GMEM_FIXED, ccacheACLlength); + InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION); + AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0, + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, + pSystemSID); + if (pTokenUser) { + AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0, + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL, + pTokenUser->User.Sid); + if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, + NULL, + NULL, + ccacheACL, + NULL)) { + DebugEvent("SetNamedSecurityInfo DACL failed: GLE = 0x%lX", GetLastError()); + ret = 1; + } + if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION, + pTokenUser->User.Sid, + NULL, + NULL, + NULL)) { + DebugEvent("SetNamedSecurityInfo Owner failed: GLE = 0x%lX", GetLastError()); + ret = 1; + } + } else { + if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, + NULL, + NULL, + ccacheACL, + NULL)) { + DebugEvent("SetNamedSecurityInfo failed: GLE = 0x%lX", GetLastError()); + ret = 1; + } + } + + if (pSystemSID) + LocalFree(pSystemSID); + if (pTokenUser) + LocalFree(pTokenUser); + if (ccacheACL) + GlobalFree(ccacheACL); + return ret; +} + +int KFW_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size) +{ + int retval = 0; + DWORD dwSize = size-1; /* leave room for nul */ + + *newfilename = '\0'; + + if ( !ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, size) && + !ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, size)) + return 1; + return 0; +} + void KFW_copy_cache_to_system_file(char * user, char * szLogonId) { @@ -769,7 +873,8 @@ KFW_copy_cache_to_system_file(char * user, char * szLogonId) krb5_principal princ = 0; krb5_ccache cc = 0; krb5_ccache ncc = 0; - + PSECURITY_ATTRIBUTES pSA = NULL; + if (!pkrb5_init_context) return; @@ -789,6 +894,8 @@ KFW_copy_cache_to_system_file(char * user, char * szLogonId) strcat(cachename, filename); + DebugEvent("KFW_Logon_Event - ccache %s", cachename); + DeleteFile(filename); code = pkrb5_init_context(&ctx); @@ -806,6 +913,8 @@ KFW_copy_cache_to_system_file(char * user, char * szLogonId) code = pkrb5_cc_initialize(ctx, ncc, princ); if (code) goto cleanup; + KFW_set_ccache_dacl(filename, NULL); + code = pkrb5_cc_copy_creds(ctx,cc,ncc); cleanup: @@ -827,7 +936,7 @@ KFW_copy_cache_to_system_file(char * user, char * szLogonId) } int -KFW_copy_system_file_to_default_cache(char * filename) +KFW_copy_file_cache_to_default_cache(char * filename) { char cachename[264] = "FILE:"; krb5_context ctx = 0; @@ -849,17 +958,31 @@ KFW_copy_system_file_to_default_cache(char * filename) if (code) ctx = 0; code = pkrb5_cc_resolve(ctx, cachename, &cc); - if (code) goto cleanup; + if (code) { + DebugEvent0("kfwcpcc krb5_cc_resolve failed"); + goto cleanup; + } code = pkrb5_cc_get_principal(ctx, cc, &princ); - if (code) goto cleanup; + if (code) { + DebugEvent0("kfwcpcc krb5_cc_get_principal failed"); + goto cleanup; + } code = pkrb5_cc_default(ctx, &ncc); + if (code) { + DebugEvent0("kfwcpcc krb5_cc_default failed"); + goto cleanup; + } if (!code) { code = pkrb5_cc_initialize(ctx, ncc, princ); if (!code) code = pkrb5_cc_copy_creds(ctx,cc,ncc); + if (code) { + DebugEvent0("kfwcpcc krb5_cc_copy_creds failed"); + goto cleanup; + } } if ( ncc ) { pkrb5_cc_close(ctx, ncc); diff --git a/src/windows/kfwlogon/kfwcpcc.c b/src/windows/kfwlogon/kfwcpcc.c index 4dbace9696..c3485c02d0 100644 --- a/src/windows/kfwlogon/kfwcpcc.c +++ b/src/windows/kfwlogon/kfwcpcc.c @@ -33,7 +33,7 @@ int main(int argc, char *argv[]) KFW_initialize(); - return KFW_copy_system_file_to_default_cache(argv[1]); + return KFW_copy_file_cache_to_default_cache(argv[1]); } diff --git a/src/windows/kfwlogon/kfwlogon.c b/src/windows/kfwlogon/kfwlogon.c index eddf273412..e815f73e00 100644 --- a/src/windows/kfwlogon/kfwlogon.c +++ b/src/windows/kfwlogon/kfwlogon.c @@ -1,5 +1,5 @@ /* -Copyright 2005 by the Massachusetts Institute of Technology +Copyright 2005,2006 by the Massachusetts Institute of Technology All rights reserved. @@ -292,6 +292,7 @@ VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo ) char szLogonId[128] = ""; DWORD count; char filename[256]; + char newfilename[256]; char commandline[512]; STARTUPINFO startupinfo; PROCESS_INFORMATION procinfo; @@ -321,14 +322,36 @@ VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo ) GetWindowsDirectory(filename, sizeof(filename)); } - if ( strlen(filename) + strlen(szLogonId) + 2 <= sizeof(filename) ) { - strcat(filename, "\\"); - strcat(filename, szLogonId); + if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) { + DebugEvent0("KFW_Logon_Event - filename too long"); + return; + } + + strcat(filename, "\\"); + strcat(filename, szLogonId); - sprintf(commandline, "kfwcpcc.exe \"%s\"", filename); + KFW_set_ccache_dacl(filename, pInfo->hToken); - GetStartupInfo(&startupinfo); - if (CreateProcessAsUser( pInfo->hToken, + KFW_obtain_user_temp_directory(pInfo->hToken, newfilename, sizeof(newfilename)); + + 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; + } + + sprintf(commandline, "kfwcpcc.exe \"%s\"", newfilename); + + GetStartupInfo(&startupinfo); + if (CreateProcessAsUser( pInfo->hToken, "kfwcpcc.exe", commandline, NULL, @@ -339,12 +362,15 @@ VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo ) NULL, &startupinfo, &procinfo)) - { - WaitForSingleObject(procinfo.hProcess, 30000); + { + DebugEvent("KFW_Logon_Event - CommandLine %s", commandline); - CloseHandle(procinfo.hThread); - CloseHandle(procinfo.hProcess); - } + WaitForSingleObject(procinfo.hProcess, 30000); + + CloseHandle(procinfo.hThread); + CloseHandle(procinfo.hProcess); + } else { + DebugEvent0("KFW_Logon_Event - CreateProcessFailed"); } DeleteFile(filename); diff --git a/src/windows/kfwlogon/kfwlogon.h b/src/windows/kfwlogon/kfwlogon.h index 34c8cc70c8..d3fa6709d6 100644 --- a/src/windows/kfwlogon/kfwlogon.h +++ b/src/windows/kfwlogon/kfwlogon.h @@ -1,6 +1,6 @@ /* -Copyright 2005 by the Massachusetts Institute of Technology +Copyright 2005,2006 by the Massachusetts Institute of Technology All rights reserved. @@ -194,6 +194,8 @@ int KFW_is_available(void); int KFW_get_cred( char * username, char * password, int lifetime, char ** reasonP ); void KFW_copy_cache_to_system_file(char * user, char * szLogonId); int KFW_destroy_tickets_for_principal(char * user); +int KFW_set_ccache_dacl(char *filename, HANDLE hUserToken); +int KFW_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size); #ifdef __cplusplus } -- cgit