#include "kfwlogon.h"
#include <windows.h>
#include <Aclapi.h>
#include <userenv.h>
#include <Sddl.h>
#include <io.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <winsock2.h>
#include <lm.h>
#include <nb30.h>
#include <errno.h>
#include <malloc.h>
DECL_FUNC_PTR(cc_initialize);
DECL_FUNC_PTR(cc_shutdown);
DECL_FUNC_PTR(cc_get_NC_info);
DECL_FUNC_PTR(cc_free_NC_info);
DECL_FUNC_PTR(Leash_get_default_lifetime);
DECL_FUNC_PTR(Leash_get_default_forwardable);
DECL_FUNC_PTR(Leash_get_default_renew_till);
DECL_FUNC_PTR(Leash_get_default_noaddresses);
DECL_FUNC_PTR(Leash_get_default_proxiable);
DECL_FUNC_PTR(Leash_get_default_publicip);
DECL_FUNC_PTR(Leash_get_default_use_krb4);
DECL_FUNC_PTR(Leash_get_default_life_min);
DECL_FUNC_PTR(Leash_get_default_life_max);
DECL_FUNC_PTR(Leash_get_default_renew_min);
DECL_FUNC_PTR(Leash_get_default_renew_max);
DECL_FUNC_PTR(Leash_get_default_renewable);
DECL_FUNC_PTR(Leash_get_default_mslsa_import);
DECL_FUNC_PTR(krb5_change_password);
DECL_FUNC_PTR(krb5_get_init_creds_opt_init);
DECL_FUNC_PTR(krb5_get_init_creds_opt_set_tkt_life);
DECL_FUNC_PTR(krb5_get_init_creds_opt_set_renew_life);
DECL_FUNC_PTR(krb5_get_init_creds_opt_set_forwardable);
DECL_FUNC_PTR(krb5_get_init_creds_opt_set_proxiable);
DECL_FUNC_PTR(krb5_get_init_creds_opt_set_address_list);
DECL_FUNC_PTR(krb5_get_init_creds_password);
DECL_FUNC_PTR(krb5_build_principal_ext);
DECL_FUNC_PTR(krb5_cc_get_name);
DECL_FUNC_PTR(krb5_cc_resolve);
DECL_FUNC_PTR(krb5_cc_default);
DECL_FUNC_PTR(krb5_cc_default_name);
DECL_FUNC_PTR(krb5_cc_set_default_name);
DECL_FUNC_PTR(krb5_cc_initialize);
DECL_FUNC_PTR(krb5_cc_destroy);
DECL_FUNC_PTR(krb5_cc_close);
DECL_FUNC_PTR(krb5_cc_store_cred);
DECL_FUNC_PTR(krb5_cc_copy_creds);
DECL_FUNC_PTR(krb5_cc_retrieve_cred);
DECL_FUNC_PTR(krb5_cc_get_principal);
DECL_FUNC_PTR(krb5_cc_start_seq_get);
DECL_FUNC_PTR(krb5_cc_next_cred);
DECL_FUNC_PTR(krb5_cc_end_seq_get);
DECL_FUNC_PTR(krb5_cc_remove_cred);
DECL_FUNC_PTR(krb5_cc_set_flags);
DECL_FUNC_PTR(krb5_cc_get_type);
DECL_FUNC_PTR(krb5_free_context);
DECL_FUNC_PTR(krb5_free_cred_contents);
DECL_FUNC_PTR(krb5_free_principal);
DECL_FUNC_PTR(krb5_get_in_tkt_with_password);
DECL_FUNC_PTR(krb5_init_context);
DECL_FUNC_PTR(krb5_parse_name);
DECL_FUNC_PTR(krb5_timeofday);
DECL_FUNC_PTR(krb5_timestamp_to_sfstring);
DECL_FUNC_PTR(krb5_unparse_name);
DECL_FUNC_PTR(krb5_get_credentials);
DECL_FUNC_PTR(krb5_mk_req);
DECL_FUNC_PTR(krb5_sname_to_principal);
DECL_FUNC_PTR(krb5_get_credentials_renew);
DECL_FUNC_PTR(krb5_free_data);
DECL_FUNC_PTR(krb5_free_data_contents);
DECL_FUNC_PTR(krb5_free_unparsed_name);
DECL_FUNC_PTR(krb5_os_localaddr);
DECL_FUNC_PTR(krb5_copy_keyblock_contents);
DECL_FUNC_PTR(krb5_copy_data);
DECL_FUNC_PTR(krb5_free_creds);
DECL_FUNC_PTR(krb5_build_principal);
DECL_FUNC_PTR(krb5_get_renewed_creds);
DECL_FUNC_PTR(krb5_get_default_config_files);
DECL_FUNC_PTR(krb5_free_config_files);
DECL_FUNC_PTR(krb5_get_default_realm);
DECL_FUNC_PTR(krb5_free_default_realm);
DECL_FUNC_PTR(krb5_free_ticket);
DECL_FUNC_PTR(krb5_decode_ticket);
DECL_FUNC_PTR(krb5_get_host_realm);
DECL_FUNC_PTR(krb5_free_host_realm);
DECL_FUNC_PTR(krb5_free_addresses);
DECL_FUNC_PTR(krb5_c_random_make_octets);
DECL_FUNC_PTR(com_err);
DECL_FUNC_PTR(error_message);
DECL_FUNC_PTR(profile_init);
DECL_FUNC_PTR(profile_release);
DECL_FUNC_PTR(profile_get_subsection_names);
DECL_FUNC_PTR(profile_free_list);
DECL_FUNC_PTR(profile_get_string);
DECL_FUNC_PTR(profile_release_string);
DECL_FUNC_PTR(OpenSCManagerA);
DECL_FUNC_PTR(OpenServiceA);
DECL_FUNC_PTR(QueryServiceStatus);
DECL_FUNC_PTR(CloseServiceHandle);
DECL_FUNC_PTR(LsaNtStatusToWinError);
DECL_FUNC_PTR(LsaConnectUntrusted);
DECL_FUNC_PTR(LsaLookupAuthenticationPackage);
DECL_FUNC_PTR(LsaCallAuthenticationPackage);
DECL_FUNC_PTR(LsaFreeReturnBuffer);
DECL_FUNC_PTR(LsaGetLogonSessionData);
FUNC_INFO ccapi_fi[] = {
MAKE_FUNC_INFO(cc_initialize),
MAKE_FUNC_INFO(cc_shutdown),
MAKE_FUNC_INFO(cc_get_NC_info),
MAKE_FUNC_INFO(cc_free_NC_info),
END_FUNC_INFO
};
FUNC_INFO leash_fi[] = {
MAKE_FUNC_INFO(Leash_get_default_lifetime),
MAKE_FUNC_INFO(Leash_get_default_renew_till),
MAKE_FUNC_INFO(Leash_get_default_forwardable),
MAKE_FUNC_INFO(Leash_get_default_noaddresses),
MAKE_FUNC_INFO(Leash_get_default_proxiable),
MAKE_FUNC_INFO(Leash_get_default_publicip),
MAKE_FUNC_INFO(Leash_get_default_use_krb4),
MAKE_FUNC_INFO(Leash_get_default_life_min),
MAKE_FUNC_INFO(Leash_get_default_life_max),
MAKE_FUNC_INFO(Leash_get_default_renew_min),
MAKE_FUNC_INFO(Leash_get_default_renew_max),
MAKE_FUNC_INFO(Leash_get_default_renewable),
END_FUNC_INFO
};
FUNC_INFO leash_opt_fi[] = {
MAKE_FUNC_INFO(Leash_get_default_mslsa_import),
END_FUNC_INFO
};
FUNC_INFO k5_fi[] = {
MAKE_FUNC_INFO(krb5_change_password),
MAKE_FUNC_INFO(krb5_get_init_creds_opt_init),
MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_tkt_life),
MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_renew_life),
MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_forwardable),
MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_proxiable),
MAKE_FUNC_INFO(krb5_get_init_creds_opt_set_address_list),
MAKE_FUNC_INFO(krb5_get_init_creds_password),
MAKE_FUNC_INFO(krb5_build_principal_ext),
MAKE_FUNC_INFO(krb5_cc_get_name),
MAKE_FUNC_INFO(krb5_cc_resolve),
MAKE_FUNC_INFO(krb5_cc_default),
MAKE_FUNC_INFO(krb5_cc_default_name),
MAKE_FUNC_INFO(krb5_cc_set_default_name),
MAKE_FUNC_INFO(krb5_cc_initialize),
MAKE_FUNC_INFO(krb5_cc_destroy),
MAKE_FUNC_INFO(krb5_cc_close),
MAKE_FUNC_INFO(krb5_cc_copy_creds),
MAKE_FUNC_INFO(krb5_cc_store_cred),
MAKE_FUNC_INFO(krb5_cc_retrieve_cred),
MAKE_FUNC_INFO(krb5_cc_get_principal),
MAKE_FUNC_INFO(krb5_cc_start_seq_get),
MAKE_FUNC_INFO(krb5_cc_next_cred),
MAKE_FUNC_INFO(krb5_cc_end_seq_get),
MAKE_FUNC_INFO(krb5_cc_remove_cred),
MAKE_FUNC_INFO(krb5_cc_set_flags),
MAKE_FUNC_INFO(krb5_cc_get_type),
MAKE_FUNC_INFO(krb5_free_context),
MAKE_FUNC_INFO(krb5_free_cred_contents),
MAKE_FUNC_INFO(krb5_free_principal),
MAKE_FUNC_INFO(krb5_get_in_tkt_with_password),
MAKE_FUNC_INFO(krb5_init_context),
MAKE_FUNC_INFO(krb5_parse_name),
MAKE_FUNC_INFO(krb5_timeofday),
MAKE_FUNC_INFO(krb5_timestamp_to_sfstring),
MAKE_FUNC_INFO(krb5_unparse_name),
MAKE_FUNC_INFO(krb5_get_credentials),
MAKE_FUNC_INFO(krb5_mk_req),
MAKE_FUNC_INFO(krb5_sname_to_principal),
MAKE_FUNC_INFO(krb5_get_credentials_renew),
MAKE_FUNC_INFO(krb5_free_data),
MAKE_FUNC_INFO(krb5_free_data_contents),
MAKE_FUNC_INFO(krb5_free_unparsed_name),
MAKE_FUNC_INFO(krb5_os_localaddr),
MAKE_FUNC_INFO(krb5_copy_keyblock_contents),
MAKE_FUNC_INFO(krb5_copy_data),
MAKE_FUNC_INFO(krb5_free_creds),
MAKE_FUNC_INFO(krb5_build_principal),
MAKE_FUNC_INFO(krb5_get_renewed_creds),
MAKE_FUNC_INFO(krb5_free_addresses),
MAKE_FUNC_INFO(krb5_get_default_config_files),
MAKE_FUNC_INFO(krb5_free_config_files),
MAKE_FUNC_INFO(krb5_get_default_realm),
MAKE_FUNC_INFO(krb5_free_default_realm),
MAKE_FUNC_INFO(krb5_free_ticket),
MAKE_FUNC_INFO(krb5_decode_ticket),
MAKE_FUNC_INFO(krb5_get_host_realm),
MAKE_FUNC_INFO(krb5_free_host_realm),
MAKE_FUNC_INFO(krb5_free_addresses),
MAKE_FUNC_INFO(krb5_c_random_make_octets),
END_FUNC_INFO
};
FUNC_INFO profile_fi[] = {
MAKE_FUNC_INFO(profile_init),
MAKE_FUNC_INFO(profile_release),
MAKE_FUNC_INFO(profile_get_subsection_names),
MAKE_FUNC_INFO(profile_free_list),
MAKE_FUNC_INFO(profile_get_string),
MAKE_FUNC_INFO(profile_release_string),
END_FUNC_INFO
};
FUNC_INFO ce_fi[] = {
MAKE_FUNC_INFO(com_err),
MAKE_FUNC_INFO(error_message),
END_FUNC_INFO
};
FUNC_INFO service_fi[] = {
MAKE_FUNC_INFO(OpenSCManagerA),
MAKE_FUNC_INFO(OpenServiceA),
MAKE_FUNC_INFO(QueryServiceStatus),
MAKE_FUNC_INFO(CloseServiceHandle),
MAKE_FUNC_INFO(LsaNtStatusToWinError),
END_FUNC_INFO
};
FUNC_INFO lsa_fi[] = {
MAKE_FUNC_INFO(LsaConnectUntrusted),
MAKE_FUNC_INFO(LsaLookupAuthenticationPackage),
MAKE_FUNC_INFO(LsaCallAuthenticationPackage),
MAKE_FUNC_INFO(LsaFreeReturnBuffer),
MAKE_FUNC_INFO(LsaGetLogonSessionData),
END_FUNC_INFO
};
static int inited = 0;
static HINSTANCE hKrb5 = 0;
static HINSTANCE hKrb524 = 0;
static HINSTANCE hSecur32 = 0;
static HINSTANCE hAdvApi32 = 0;
static HINSTANCE hComErr = 0;
static HINSTANCE hService = 0;
static HINSTANCE hProfile = 0;
static HINSTANCE hLeash = 0;
static HINSTANCE hLeashOpt = 0;
static HINSTANCE hCCAPI = 0;
static DWORD TraceOption = 0;
static HANDLE hDLL;
BOOL IsDebugLogging(void)
{
DWORD LSPsize;
HKEY NPKey;
DWORD dwDebug = FALSE;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Services\\MIT Kerberos\\NetworkProvider",
0, KEY_QUERY_VALUE, &NPKey) == ERROR_SUCCESS)
{
LSPsize=sizeof(dwDebug);
if (RegQueryValueEx(NPKey, "Debug", NULL, NULL, (LPBYTE)&dwDebug, &LSPsize) != ERROR_SUCCESS)
{
dwDebug = FALSE;
}
RegCloseKey (NPKey);
}
return(dwDebug ? TRUE : FALSE);
}
void DebugEvent0(char *a)
{
HANDLE h; char *ptbuf[1];
if (IsDebugLogging()) {
h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME);
if (h) {
ptbuf[0] = a;
ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
DeregisterEventSource(h);
}
}
}
#define MAXBUF_ 512
void DebugEvent(char *b,...)
{
HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
va_list marker;
if (IsDebugLogging()) {
h = RegisterEventSource(NULL, KFW_LOGON_EVENT_NAME);
if (h) {
va_start(marker,b);
StringCbVPrintf(buf, MAXBUF_+1,b,marker);
buf[MAXBUF_] = '\0';
ptbuf[0] = buf;
ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
DeregisterEventSource(h);
va_end(marker);
}
}
}
void
UnloadFuncs(
FUNC_INFO fi[],
HINSTANCE h
)
{
int n;
if (fi)
for (n = 0; fi[n].func_ptr_var; n++)
*(fi[n].func_ptr_var) = 0;
if (h) FreeLibrary(h);
}
int
LoadFuncs(
const char* dll_name,
FUNC_INFO fi[],
HINSTANCE* ph, int* pindex, int cleanup, int go_on, int silent )
{
HINSTANCE h;
int i, n, last_i;
int error = 0;
UINT em;
if (ph) *ph = 0;
if (pindex) *pindex = -1;
for (n = 0; fi[n].func_ptr_var; n++)
*(fi[n].func_ptr_var) = 0;
if (silent)
em = SetErrorMode(SEM_FAILCRITICALERRORS);
h = LoadLibrary(dll_name);
if (silent)
SetErrorMode(em);
if (!h)
return 0;
last_i = -1;
for (i = 0; (go_on || !error) && (i < n); i++)
{
void* p = (void*)GetProcAddress(h, fi[i].func_name);
if (!p)
error = 1;
else
{
last_i = i;
*(fi[i].func_ptr_var) = p;
}
}
if (pindex) *pindex = last_i;
if (error && cleanup && !go_on) {
for (i = 0; i < n; i++) {
*(fi[i].func_ptr_var) = 0;
}
FreeLibrary(h);
return 0;
}
if (ph) *ph = h;
if (error) return 0;
return 1;
}
static HANDLE hInitMutex = NULL;
static BOOL bInit = FALSE;
void
KFW_initialize(void)
{
static int inited = 0;
if ( !inited ) {
char mutexName[MAX_PATH];
HANDLE hMutex = NULL;
sprintf(mutexName, "AFS KFW Init pid=%d", getpid());
hMutex = CreateMutex( NULL, TRUE, mutexName );
if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
return;
}
}
if ( !inited ) {
inited = 1;
LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0);
LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0);
LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0);
LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1);
LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0);
LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0);
LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0);
LoadFuncs(LEASH_DLL, leash_opt_fi, &hLeashOpt, 0, 1, 0, 0);
}
ReleaseMutex(hMutex);
CloseHandle(hMutex);
}
}
void
KFW_cleanup(void)
{
if (hLeashOpt)
FreeLibrary(hLeashOpt);
if (hCCAPI)
FreeLibrary(hCCAPI);
if (hLeash)
FreeLibrary(hLeash);
if (hKrb524)
FreeLibrary(hKrb524);
if (hSecur32)
FreeLibrary(hSecur32);
if (hService)
FreeLibrary(hService);
if (hComErr)
FreeLibrary(hComErr);
if (hProfile)
FreeLibrary(hProfile);
if (hKrb5)
FreeLibrary(hKrb5);
}
int
KFW_is_available(void)
{
KFW_initialize();
if ( hKrb5 && hComErr && hService &&
#ifdef USE_MS2MIT
hSecur32 &&
#endif
hProfile && hLeash && hCCAPI )
return TRUE;
return FALSE;
}
int
KFW_get_ccache(krb5_context alt_ctx, krb5_principal principal, krb5_ccache * cc)
{
krb5_context ctx;
char * pname = 0;
char * ccname = 0;
krb5_error_code code;
if (!pkrb5_init_context)
return 0;
if ( alt_ctx ) {
ctx = alt_ctx;
} else {
code = pkrb5_init_context(&ctx);
if (code) goto cleanup;
}
if ( principal ) {
code = pkrb5_unparse_name(ctx, principal, &pname);
if (code) goto cleanup;
ccname = (char *)malloc(strlen(pname) + 5);
sprintf(ccname,"API:%s",pname);
DebugEvent0(ccname);
code = pkrb5_cc_resolve(ctx, ccname, cc);
} else {
code = pkrb5_cc_default(ctx, cc);
if (code) goto cleanup;
}
cleanup:
if (ccname)
free(ccname);
if (pname)
pkrb5_free_unparsed_name(ctx,pname);
if (ctx && (ctx != alt_ctx))
pkrb5_free_context(ctx);
return(code);
}
int
KFW_kinit( krb5_context alt_ctx,
krb5_ccache alt_cc,
HWND hParent,
char *principal_name,
char *password,
krb5_deltat lifetime,
DWORD forwardable,
DWORD proxiable,
krb5_deltat renew_life,
DWORD addressless,
DWORD publicIP
)
{
krb5_error_code code = 0;
krb5_context ctx = 0;
krb5_ccache cc = 0;
krb5_principal me = 0;
char* name = 0;
krb5_creds my_creds;
krb5_get_init_creds_opt options;
krb5_address ** addrs = NULL;
int i = 0, addr_count = 0;
if (!pkrb5_init_context)
return 0;
pkrb5_get_init_creds_opt_init(&options);
memset(&my_creds, 0, sizeof(my_creds));
if (alt_ctx)
{
ctx = alt_ctx;
}
else
{
code = pkrb5_init_context(&ctx);
if (code) goto cleanup;
}
if ( alt_cc ) {
cc = alt_cc;
} else {
code = pkrb5_cc_default(ctx, &cc);
if (code) goto cleanup;
}
code = pkrb5_parse_name(ctx, principal_name, &me);
if (code)
goto cleanup;
code = pkrb5_unparse_name(ctx, me, &name);
if (code)
goto cleanup;
if (lifetime == 0)
lifetime = pLeash_get_default_lifetime();
lifetime *= 60;
if (renew_life > 0)
renew_life *= 60;
if (lifetime)
pkrb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
pkrb5_get_init_creds_opt_set_forwardable(&options,
forwardable ? 1 : 0);
pkrb5_get_init_creds_opt_set_proxiable(&options,
proxiable ? 1 : 0);
pkrb5_get_init_creds_opt_set_renew_life(&options,
renew_life);
if (addressless)
pkrb5_get_init_creds_opt_set_address_list(&options,NULL);
else {
if (publicIP)
{
krb5_address ** local_addrs=NULL;
DWORD netIPAddr;
pkrb5_os_localaddr(ctx, &local_addrs);
while ( local_addrs[i++] );
addr_count = i + 1;
addrs = (krb5_address **) malloc((addr_count+1) * sizeof(krb5_address *));
if ( !addrs ) {
pkrb5_free_addresses(ctx, local_addrs);
goto cleanup;
}
memset(addrs, 0, sizeof(krb5_address *) * (addr_count+1));
i = 0;
while ( local_addrs[i] ) {
addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
if (addrs[i] == NULL) {
pkrb5_free_addresses(ctx, local_addrs);
goto cleanup;
}
addrs[i]->magic = local_addrs[i]->magic;
addrs[i]->addrtype = local_addrs[i]->addrtype;
addrs[i]->length = local_addrs[i]->length;
addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
if (!addrs[i]->contents) {
pkrb5_free_addresses(ctx, local_addrs);
goto cleanup;
}
memcpy(addrs[i]->contents,local_addrs[i]->contents,
local_addrs[i]->length);
i++;
}
pkrb5_free_addresses(ctx, local_addrs);
addrs[i] = (krb5_address *)malloc(sizeof(krb5_address));
if (addrs[i] == NULL)
goto cleanup;
addrs[i]->magic = KV5M_ADDRESS;
addrs[i]->addrtype = AF_INET;
addrs[i]->length = 4;
addrs[i]->contents = (unsigned char *)malloc(addrs[i]->length);
if (!addrs[i]->contents)
goto cleanup;
netIPAddr = htonl(publicIP);
memcpy(addrs[i]->contents,&netIPAddr,4);
pkrb5_get_init_creds_opt_set_address_list(&options,addrs);
}
}
code = pkrb5_get_init_creds_password(ctx,
&my_creds,
me,
password, NULL, hParent, 0, 0, &options);
if (code)
goto cleanup;
code = pkrb5_cc_initialize(ctx, cc, me);
if (code)
goto cleanup;
code = pkrb5_cc_store_cred(ctx, cc, &my_creds);
if (code)
goto cleanup;
cleanup:
if ( addrs ) {
for ( i=0;i<addr_count;i++ ) {
if ( addrs[i] ) {
if ( addrs[i]->contents )
free(addrs[i]->contents);
free(addrs[i]);
}
}
}
if (my_creds.client == me)
my_creds.client = 0;
pkrb5_free_cred_contents(ctx, &my_creds);
if (name)
pkrb5_free_unparsed_name(ctx, name);
if (me)
pkrb5_free_principal(ctx, me);
if (cc && (cc != alt_cc))
pkrb5_cc_close(ctx, cc);
if (ctx && (ctx != alt_ctx))
pkrb5_free_context(ctx);
return(code);
}
int
KFW_get_cred( char * username,
char * password,
int lifetime,
char ** reasonP )
{
krb5_context ctx = 0;
krb5_ccache cc = 0;
char * realm = 0;
krb5_principal principal = 0;
char * pname = 0;
krb5_error_code code;
if (!pkrb5_init_context || !username || !password || !password[0])
return 0;
DebugEvent0(username);
code = pkrb5_init_context(&ctx);
if ( code ) goto cleanup;
code = pkrb5_get_default_realm(ctx, &realm);
if (realm) {
pname = malloc(strlen(username) + strlen(realm) + 2);
if (!pname)
goto cleanup;
strcpy(pname, username);
strcat(pname, "@");
strcat(pname, realm);
} else {
goto cleanup;
}
DebugEvent0(realm);
DebugEvent0(pname);
code = pkrb5_parse_name(ctx, pname, &principal);
if ( code ) goto cleanup;
DebugEvent0("parsed name");
code = KFW_get_ccache(ctx, principal, &cc);
if ( code ) goto cleanup;
DebugEvent0("got ccache");
if ( lifetime == 0 )
lifetime = pLeash_get_default_lifetime();
DebugEvent0("got lifetime");
code = KFW_kinit( ctx, cc, HWND_DESKTOP,
pname,
password,
lifetime,
pLeash_get_default_forwardable(),
pLeash_get_default_proxiable(),
pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
pLeash_get_default_noaddresses(),
pLeash_get_default_publicip());
DebugEvent0("kinit returned");
if ( code ) goto cleanup;
cleanup:
if ( pname )
free(pname);
if ( realm )
pkrb5_free_default_realm(ctx, realm);
if ( cc )
pkrb5_cc_close(ctx, cc);
if ( code && reasonP ) {
*reasonP = (char *)perror_message(code);
}
return(code);
}
int KFW_set_ccache_dacl(char *filename, HANDLE hUserToken)
{
PSID pSystemSID = NULL;
DWORD SystemSIDlength = 0, UserSIDlength = 0;
PACL ccacheACL = NULL;
DWORD ccacheACLlength = 0;
PTOKEN_USER pTokenUser = NULL;
DWORD retLen;
DWORD gle;
int ret = 0;
if (!filename) {
DebugEvent0("KFW_set_ccache_dacl - invalid parms");
return 1;
}
DebugEvent0("KFW_set_ccache_dacl");
if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
DebugEvent("KFW_set_ccache_dacl - ConvertStringSidToSid GLE = 0x%x", GetLastError());
ret = 1;
goto cleanup;
}
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 = (PACL) LocalAlloc(LPTR, ccacheACLlength);
if (!ccacheACL) {
DebugEvent("KFW_set_ccache_dacl - LocalAlloc GLE = 0x%x", GetLastError());
ret = 1;
goto cleanup;
}
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)) {
gle = GetLastError();
DebugEvent("SetNamedSecurityInfo DACL (1) failed: GLE = 0x%lX", gle);
if (gle != ERROR_NO_TOKEN)
ret = 1;
}
if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION,
pTokenUser->User.Sid,
NULL,
NULL,
NULL)) {
gle = GetLastError();
DebugEvent("SetNamedSecurityInfo OWNER (2) failed: GLE = 0x%lX", gle);
if (gle != ERROR_NO_TOKEN)
ret = 1;
}
} else {
if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
NULL,
NULL,
ccacheACL,
NULL)) {
gle = GetLastError();
DebugEvent("SetNamedSecurityInfo DACL (3) failed: GLE = 0x%lX", gle);
if (gle != ERROR_NO_TOKEN)
ret = 1;
}
}
cleanup:
if (pSystemSID)
LocalFree(pSystemSID);
if (pTokenUser)
LocalFree(pTokenUser);
if (ccacheACL)
LocalFree(ccacheACL);
return ret;
}
int KFW_set_ccache_dacl_with_user_sid(char *filename, PSID pUserSID)
{
PSID pSystemSID = NULL;
DWORD SystemSIDlength = 0, UserSIDlength = 0;
PACL ccacheACL = NULL;
DWORD ccacheACLlength = 0;
DWORD gle;
int ret = 0;
if (!filename) {
DebugEvent0("KFW_set_ccache_dacl_with_user_sid - invalid parms");
return 1;
}
DebugEvent0("KFW_set_ccache_dacl_with_user_sid");
if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
DebugEvent("KFW_set_ccache_dacl - ConvertStringSidToSid GLE = 0x%x", GetLastError());
ret = 1;
goto cleanup;
}
SystemSIDlength = GetLengthSid(pSystemSID);
ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
+ SystemSIDlength - sizeof(DWORD);
if (pUserSID) {
UserSIDlength = GetLengthSid(pUserSID);
ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
- sizeof(DWORD);
}
ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
if (!ccacheACL) {
DebugEvent("KFW_set_ccache_dacl - LocalAlloc GLE = 0x%x", GetLastError());
ret = 1;
goto cleanup;
}
InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
pSystemSID);
if (pUserSID) {
AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
pUserSID);
if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
NULL,
NULL,
ccacheACL,
NULL)) {
gle = GetLastError();
DebugEvent("SetNamedSecurityInfo DACL (4) failed: GLE = 0x%lX", gle);
if (gle != ERROR_NO_TOKEN)
ret = 1;
}
if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
OWNER_SECURITY_INFORMATION,
pUserSID,
NULL,
NULL,
NULL)) {
gle = GetLastError();
DebugEvent("SetNamedSecurityInfo OWNER (5) failed: GLE = 0x%lX", gle);
if (gle != ERROR_NO_TOKEN)
ret = 1;
}
} else {
if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
NULL,
NULL,
ccacheACL,
NULL)) {
gle = GetLastError();
DebugEvent("SetNamedSecurityInfo DACL (6) failed: GLE = 0x%lX", gle);
if (gle != ERROR_NO_TOKEN)
ret = 1;
}
}
cleanup:
if (pSystemSID)
LocalFree(pSystemSID);
if (ccacheACL)
LocalFree(ccacheACL);
return ret;
}
int KFW_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
{
int retval = 0;
DWORD dwSize = size-1;
DWORD dwLen = 0;
if (!hUserToken || !newfilename || size <= 0)
return 1;
*newfilename = '\0';
dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
if ( !dwLen || dwLen > dwSize )
dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
if ( !dwLen || dwLen > dwSize )
return 1;
newfilename[dwSize] = '\0';
return 0;
}
void
KFW_copy_cache_to_system_file(const char * user, const char * filename)
{
char cachename[MAX_PATH + 8] = "FILE:";
krb5_context ctx = 0;
krb5_error_code code;
krb5_principal princ = 0;
krb5_ccache cc = 0;
krb5_ccache ncc = 0;
PSECURITY_ATTRIBUTES pSA = NULL;
if (!pkrb5_init_context || !user || !filename)
return;
strncat(cachename, filename, sizeof(cachename));
cachename[sizeof(cachename)-1] = '\0';
DebugEvent("KFW_Logon_Event - ccache %s", cachename);
DeleteFile(filename);
code = pkrb5_init_context(&ctx);
if (code) goto cleanup;
code = pkrb5_parse_name(ctx, user, &princ);
if (code) goto cleanup;
code = KFW_get_ccache(ctx, princ, &cc);
if (code) goto cleanup;
code = pkrb5_cc_resolve(ctx, cachename, &ncc);
if (code) goto cleanup;
code = pkrb5_cc_initialize(ctx, ncc, princ);
if (code) goto cleanup;
code = KFW_set_ccache_dacl(filename, NULL);
if (code) goto cleanup;
code = pkrb5_cc_copy_creds(ctx,cc,ncc);
cleanup:
if ( cc ) {
pkrb5_cc_close(ctx, cc);
cc = 0;
}
if ( ncc ) {
pkrb5_cc_close(ctx, ncc);
ncc = 0;
}
if ( princ ) {
pkrb5_free_principal(ctx, princ);
princ = 0;
}
if (ctx)
pkrb5_free_context(ctx);
}
int
KFW_copy_file_cache_to_default_cache(char * filename)
{
char cachename[MAX_PATH + 8] = "FILE:";
krb5_context ctx = 0;
krb5_error_code code;
krb5_principal princ = 0;
krb5_ccache cc = 0;
krb5_ccache ncc = 0;
int retval = 1;
if (!pkrb5_init_context || !filename)
return 1;
if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
return 1;
code = pkrb5_init_context(&ctx);
if (code) return 1;
strcat(cachename, filename);
code = pkrb5_cc_resolve(ctx, cachename, &cc);
if (code) {
DebugEvent0("kfwcpcc krb5_cc_resolve failed");
goto cleanup;
}
code = pkrb5_cc_get_principal(ctx, cc, &princ);
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);
ncc = 0;
}
retval=0;
cleanup:
if ( cc ) {
pkrb5_cc_close(ctx, cc);
cc = 0;
}
DeleteFile(filename);
if ( princ ) {
pkrb5_free_principal(ctx, princ);
princ = 0;
}
if (ctx)
pkrb5_free_context(ctx);
return 0;
}
int
KFW_copy_file_cache_to_api_cache(char * filename)
{
char cachename[MAX_PATH + 8] = "FILE:";
krb5_context ctx = 0;
krb5_error_code code;
krb5_principal princ = 0;
krb5_ccache cc = 0;
krb5_ccache ncc = 0;
char *name = NULL;
int retval = 1;
if (!pkrb5_init_context || !filename)
return 1;
if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
return 1;
code = pkrb5_init_context(&ctx);
if (code) return 1;
strcat(cachename, filename);
code = pkrb5_cc_resolve(ctx, cachename, &cc);
if (code) {
DebugEvent0("kfwcpcc krb5_cc_resolve failed");
goto cleanup;
}
code = pkrb5_cc_get_principal(ctx, cc, &princ);
if (code) {
DebugEvent0("kfwcpcc krb5_cc_get_principal failed");
goto cleanup;
}
code = pkrb5_unparse_name(ctx, princ, &name);
if (code) {
DebugEvent0("kfwcpcc krb5_unparse_name failed");
goto cleanup;
}
sprintf(cachename, "API:%s", name);
code = pkrb5_cc_resolve(ctx, cachename, &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);
ncc = 0;
}
retval=0;
cleanup:
if (name)
pkrb5_free_unparsed_name(ctx, name);
if ( cc ) {
pkrb5_cc_close(ctx, cc);
cc = 0;
}
DeleteFile(filename);
if ( princ ) {
pkrb5_free_principal(ctx, princ);
princ = 0;
}
if (ctx)
pkrb5_free_context(ctx);
return 0;
}
int
KFW_destroy_tickets_for_principal(char * user)
{
krb5_context ctx = 0;
krb5_error_code code;
krb5_principal princ = 0;
krb5_ccache cc = 0;
if (!pkrb5_init_context)
return 0;
code = pkrb5_init_context(&ctx);
if (code) return 1;
code = pkrb5_parse_name(ctx, user, &princ);
if (code) goto loop_cleanup;
code = KFW_get_ccache(ctx, princ, &cc);
if (code) goto loop_cleanup;
code = pkrb5_cc_destroy(ctx, cc);
if (!code) cc = 0;
loop_cleanup:
if ( cc ) {
pkrb5_cc_close(ctx, cc);
cc = 0;
}
if ( princ ) {
pkrb5_free_principal(ctx, princ);
princ = 0;
}
pkrb5_free_context(ctx);
return 0;
}
void
KFW_cleanup_orphaned_caches(void)
{
char * temppath = NULL;
char * curdir = NULL;
DWORD count, count2;
WIN32_FIND_DATA FindFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;
FILETIME now;
ULARGE_INTEGER uli_now;
FILETIME expired;
count = GetTempPath(0, NULL);
if (count <= 0)
return;
temppath = (char *) malloc(count);
if (!temppath)
goto cleanup;
count2 = GetTempPath(count, temppath);
if (count2 <= 0 || count2 > count)
goto cleanup;
count = GetCurrentDirectory(0, NULL);
curdir = (char *)malloc(count);
if (!curdir)
goto cleanup;
count2 = GetCurrentDirectory(count, curdir);
if (count2 <= 0 || count2 > count)
goto cleanup;
if (!SetCurrentDirectory(temppath))
goto cleanup;
GetSystemTimeAsFileTime(&now);
uli_now.u.LowPart = now.dwLowDateTime;
uli_now.u.HighPart = now.dwHighDateTime;
uli_now.QuadPart -= 3000000000;
expired.dwLowDateTime = uli_now.u.LowPart;
expired.dwHighDateTime = uli_now.u.HighPart;
hFind = FindFirstFile("kfwlogon-*", &FindFileData);
if (hFind != INVALID_HANDLE_VALUE) {
do {
if (CompareFileTime(&FindFileData.ftCreationTime, &expired) < 0) {
DebugEvent("Deleting orphaned cache file: \"%s\"", FindFileData.cFileName);
DeleteFile(FindFileData.cFileName);
}
} while ( FindNextFile(hFind, &FindFileData) );
}
SetCurrentDirectory(curdir);
cleanup:
if (temppath)
free(temppath);
if (hFind != INVALID_HANDLE_VALUE)
FindClose(hFind);
if (curdir)
free(curdir);
}