From: Jeffrey Altman Date: Tue, 4 May 2004 23:48:15 +0000 (+0000) Subject: afskfw-library-20040504 X-Git-Tag: openafs-devel-1_3_64~36 X-Git-Url: https://git.michaelhowe.org/gitweb/?a=commitdiff_plain;h=14005bc769bbca0a1944aacce1f4c9aae7d55d9b;p=packages%2Fo%2Fopenafs.git afskfw-library-20040504 Migrate KFW functionality from src/WINNT/client_creds/afskfw* into a a new library to be shared by afslogon.dll, afscreds.exe Add KFW support to afslogon.dll ==================== This delta was composed from multiple commits as part of the CVS->Git migration. The checkin message with each commit was inconsistent. The following are the additional commit messages. ==================== Migrate KFW functionality from src/WINNT/client_creds/afskfw* into a a new library to be shared by afslogon.dll, afscreds.exe Move IP Address Change Monitor into new source files. Add smbname support to the KFW set token functionality in afscreds.exe --- diff --git a/src/WINNT/afsd/NTMakefile b/src/WINNT/afsd/NTMakefile index a0c28404d..a99b91f14 100644 --- a/src/WINNT/afsd/NTMakefile +++ b/src/WINNT/afsd/NTMakefile @@ -5,7 +5,7 @@ # License. For details, see the LICENSE file in the top-level source # directory or online at http://www.openafs.org/dl/license10.html -AFSDEV_AUXCDEFINES = $(AFSDEV_AUXCDEFINES) /D"_AFXDLL" +AFSDEV_AUXCDEFINES = $(AFSDEV_AUXCDEFINES) /D"_AFXDLL" -I..\kfw\inc\loadfuncs -I..\kfw\inc\krb5 -I..\kfw\inc\leash AFSDEV_NETGUI = 1 RELDIR=WINNT\afsd !INCLUDE ..\..\config\NTMakefile.$(SYS_NAME) @@ -63,7 +63,8 @@ INCFILES =\ $(INCFILEDIR)\cm_buf.h \ $(INCFILEDIR)\cm_freelance.h \ $(INCFILEDIR)\afsd_eventlog.h \ - $(INCFILEDIR)\afsd_eventmessages.h + $(INCFILEDIR)\afsd_eventmessages.h \ + $(INCFILEDIR)\afskfw.h IDLFILES =\ afsrpc.h $(OUT)\afsrpc_c.obj @@ -174,6 +175,32 @@ $(CONF_DLLFILE): $(CONFOBJS) $(OUT)\libafsconf.res $(CONF_DLLLIBS) $(COPY) $*.lib $(ILIBDIR) $(DEL) $*.lib $*.exp +############################################################################ +# lanahelper.lib + +LANAHELPERLIB = $(DESTDIR)\lib\lanahelper.lib + +LANAHELPERLIB_OBJS =\ + $(OUT)\lanahelper.obj + +$(LANAHELPERLIB_OBJS): + +$(LANAHELPERLIB): $(LANAHELPERLIB_OBJS) + $(LIBARCH) netapi32.lib + +############################################################################ +# afskfw.lib + +AFSKFWLIB = $(DESTDIR)\lib\afskfw.lib + +AFSKFWLIB_OBJS =\ + $(OUT)\afskfw.obj + +$(AFSKFWLIB_OBJS): + +$(AFSKFWLIB): $(AFSKFWLIB_OBJS) + $(LIBARCH) + ############################################################################ # afslogon.dll @@ -185,7 +212,10 @@ LOGON_DLLOBJS =\ LOGON_DLLLIBS =\ $(DESTDIR)\lib\afsauthent.lib \ - $(DESTDIR)\lib\libafsconf.lib + $(DESTDIR)\lib\libafsconf.lib \ + $(DESTDIR)\lib\afsrxkad.lib \ + $(DESTDIR)\lib\afsdes.lib \ + $(AFSKFWLIB) $(LOGON_DLLFILE): $(LOGON_DLLOBJS) $(LOGON_DLLLIBS) $(DLLGUILINK) $(LOGONLINKFLAGS) -def:afslogon.def dnsapi.lib secur32.lib @@ -212,19 +242,6 @@ $(LOG95_DLLFILE): $(LOG95_DLLOBJS) $(LOG95_DLLLIBS) $(COPY) $*.lib $(DESTDIR)\lib $(DEL) $*.lib $*.exp -############################################################################ -# lanahelper.lib - -LANAHELPERLIB = $(DESTDIR)\lib\lanahelper.lib - -LANAHELPERLIB_OBJS =\ - $(OUT)\lanahelper.obj - -$(LANAHELPERLIB_OBJS): - -$(LANAHELPERLIB): $(LANAHELPERLIB_OBJS) - $(LIBARCH) netapi32.lib - ############################################################################ # Install target; primary makefile target diff --git a/src/WINNT/afsd/afskfw-int.h b/src/WINNT/afsd/afskfw-int.h new file mode 100644 index 000000000..329b83689 --- /dev/null +++ b/src/WINNT/afsd/afskfw-int.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2003 SkyRope, LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Skyrope, LLC nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission from Skyrope, LLC. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Portions of this code are derived from portions of the MIT + * Leash Ticket Manager and LoadFuncs utilities. For these portions the + * following copyright applies. + * + * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, 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 M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#ifndef AFSKRB5_INT_H +#define AFSKRB5_INT_H + +#include +#ifdef USE_MS2MIT +#define SECURITY_WIN32 +#include +#include +#endif /* USE_MS2MIT */ +#include +#include +#include +#include + +#ifdef USE_MS2MIT +#include +#endif /* USE_MS2MIT */ + +#include +#include + +#include + +/* Defined in the KRBV4W32 version of krb.h but not the Kerberos V version */ +/* Required for some of the loadfuncs headers */ +typedef struct ktext far *KTEXT; +typedef struct ktext far *KTEXT_FP; +#include + +/* AFS has its own version of com_err.h */ +typedef afs_int32 errcode_t; + +#include +#include +#include +#include +#include +#include +#include + +// service definitions +#define SERVICE_DLL "advapi32.dll" +typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD); +typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD); +typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS); +typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE); + +#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ +#define LSA_CCNAME "MSLSA:" + +#define KTC_ERROR 11862784L +#define KTC_TOOBIG 11862785L +#define KTC_INVAL 11862786L +#define KTC_NOENT 11862787L +#define KTC_PIOCTLFAIL 11862788L +#define KTC_NOPIOCTL 11862789L +#define KTC_NOCELL 11862790L +#define KTC_NOCM 11862791L + +/* User Query data structures and functions */ + +struct textField { + char * buf; /* Destination buffer address */ + int len; /* Destination buffer length */ + char * label; /* Label for this field */ + char * def; /* Default response for this field */ + int echo; /* 0 = no, 1 = yes, 2 = asterisks */ +}; + +#define ID_TEXT 150 +#define ID_MID_TEXT 300 + +struct principal_ccache_data { + struct principal_ccache_data * next; + char * principal; + char * ccache_name; + int from_lsa; + int expired; + int expiration_time; + int renew; +}; + +struct cell_principal_map { + struct cell_principal_map * next; + char * cell; + char * principal; + int active; +}; + +/* In order to avoid including the private CCAPI headers */ +typedef int cc_int32; + +#define CC_API_VER_1 1 +#define CC_API_VER_2 2 + +#define CCACHE_API cc_int32 + +/* +** The Official Error Codes +*/ +#define CC_NOERROR 0 +#define CC_BADNAME 1 +#define CC_NOTFOUND 2 +#define CC_END 3 +#define CC_IO 4 +#define CC_WRITE 5 +#define CC_NOMEM 6 +#define CC_FORMAT 7 +#define CC_LOCKED 8 +#define CC_BAD_API_VERSION 9 +#define CC_NO_EXIST 10 +#define CC_NOT_SUPP 11 +#define CC_BAD_PARM 12 +#define CC_ERR_CACHE_ATTACH 13 +#define CC_ERR_CACHE_RELEASE 14 +#define CC_ERR_CACHE_FULL 15 +#define CC_ERR_CRED_VERSION 16 + +enum { + CC_CRED_VUNKNOWN = 0, // For validation + CC_CRED_V4 = 1, + CC_CRED_V5 = 2, + CC_CRED_VMAX = 3 // For validation +}; + +typedef struct opaque_dll_control_block_type* apiCB; +typedef struct _infoNC { + char* name; + char* principal; + cc_int32 vers; +} infoNC; + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_initialize, + ( + apiCB** cc_ctx, // < DLL's primary control structure. + // returned here, passed everywhere else + cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1) + cc_int32* api_supported, // < if ~NULL, max ver supported by DLL + const char** vendor // < if ~NULL, vendor name in read only C string + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_shutdown, + ( + apiCB** cc_ctx // <> DLL's primary control structure. NULL after + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_get_NC_info, + ( + apiCB* cc_ctx, // > DLL's primary control structure + struct _infoNC*** ppNCi // < (NULL before call) null terminated, + // list of a structs (free via cc_free_infoNC()) + ) +); + +TYPEDEF_FUNC( +CCACHE_API, +CALLCONV_C, +cc_free_NC_info, + ( + apiCB* cc_ctx, + struct _infoNC*** ppNCi // < free list of structs returned by + // cc_get_cache_names(). set to NULL on return + ) +); +#define CCAPI_DLL "krbcc32.dll" + +/* Function Prototypes */ +DWORD GetServiceStatus(LPSTR, LPSTR, DWORD *); +void KFW_AFS_error(LONG, LPCSTR); + +void UnloadFuncs(FUNC_INFO [], HINSTANCE); +int LoadFuncs(const char*, FUNC_INFO [], HINSTANCE*, int*, int, int, int); +int KFW_get_ccache(krb5_context, krb5_principal, krb5_ccache *); +int KFW_error(krb5_error_code, LPCSTR, int, krb5_context *, krb5_ccache *); +int KFW_kinit(krb5_context, krb5_ccache, HWND, char *, char *, krb5_deltat, + DWORD, DWORD, krb5_deltat, DWORD, DWORD); +int KFW_renew(krb5_context, krb5_ccache); +int KFW_destroy(krb5_context, krb5_ccache); +BOOL KFW_ms2mit(krb5_context, krb5_ccache, BOOL); +int KFW_AFS_unlog(void); +int KFW_AFS_klog(krb5_context, krb5_ccache, char*, char*, char*, int, char*); +void KFW_import_ccache_data(void); +BOOL MSLSA_IsKerberosLogon(); +char *afs_realm_of_cell(struct afsconf_cell *); +#endif /* AFSKFW_INT_H */ diff --git a/src/WINNT/afsd/afskfw.c b/src/WINNT/afsd/afskfw.c new file mode 100644 index 000000000..38402c2af --- /dev/null +++ b/src/WINNT/afsd/afskfw.c @@ -0,0 +1,3209 @@ +/* + * Copyright (c) 2003 SkyRope, LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Skyrope, LLC nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission from Skyrope, LLC. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Portions of this code are derived from portions of the MIT + * Leash Ticket Manager and LoadFuncs utilities. For these portions the + * following copyright applies. + * + * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, 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 M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + + +#define USE_MS2MIT +#define USE_KRB4 +#include "afskfw-int.h" +#include "afskfw.h" + +#include +#include /* for life_to_time */ + +/* + * TIMING _____________________________________________________________________ + * + */ + +#define cminREMIND_TEST 1 // test every minute for expired creds +#define cminREMIND_WARN 15 // warn if creds expire in 15 minutes +#define cminRENEW 20 // renew creds when there are 20 minutes remaining +#define cminMINLIFE 30 // minimum life of Kerberos creds + +#define c100ns1SECOND (LONGLONG)10000000 +#define cmsec1SECOND 1000 +#define cmsec1MINUTE 60000 +#define csec1MINUTE 60 + +/* Function Pointer Declarations for Delayed Loading */ +// CCAPI +DECL_FUNC_PTR(cc_initialize); +DECL_FUNC_PTR(cc_shutdown); +DECL_FUNC_PTR(cc_get_NC_info); +DECL_FUNC_PTR(cc_free_NC_info); + +// leash functions +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); + +// krb5 functions +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_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); + +// Krb524 functions +DECL_FUNC_PTR(krb524_init_ets); +DECL_FUNC_PTR(krb524_convert_creds_kdc); + +// krb4 functions +DECL_FUNC_PTR(krb_get_cred); +DECL_FUNC_PTR(tkt_string); +DECL_FUNC_PTR(krb_get_tf_realm); +DECL_FUNC_PTR(krb_mk_req); + +// ComErr functions +DECL_FUNC_PTR(com_err); +DECL_FUNC_PTR(error_message); + +// Profile functions +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); + +// Service functions +DECL_FUNC_PTR(OpenSCManagerA); +DECL_FUNC_PTR(OpenServiceA); +DECL_FUNC_PTR(QueryServiceStatus); +DECL_FUNC_PTR(CloseServiceHandle); +#ifdef USE_MS2MIT +DECL_FUNC_PTR(LsaNtStatusToWinError); +#endif /* USE_MS2MIT */ + +#ifdef USE_MS2MIT +// LSA Functions +DECL_FUNC_PTR(LsaConnectUntrusted); +DECL_FUNC_PTR(LsaLookupAuthenticationPackage); +DECL_FUNC_PTR(LsaCallAuthenticationPackage); +DECL_FUNC_PTR(LsaFreeReturnBuffer); +DECL_FUNC_PTR(LsaGetLogonSessionData); +#endif /* USE_MS2MIT */ + +// AFS36 Token Functions +DECL_FUNC_PTR(ktc_ListTokens); +DECL_FUNC_PTR(ktc_GetToken); +DECL_FUNC_PTR(ktc_SetToken); +DECL_FUNC_PTR(ktc_ForgetAllTokens); + +// AFS36 Config Functions +DECL_FUNC_PTR(cm_SearchCellFile); +DECL_FUNC_PTR(cm_GetRootCellName); + +// CCAPI +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 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_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 k4_fi[] = { + MAKE_FUNC_INFO(krb_get_cred), + MAKE_FUNC_INFO(krb_get_tf_realm), + MAKE_FUNC_INFO(krb_mk_req), + MAKE_FUNC_INFO(tkt_string), + END_FUNC_INFO +}; + +FUNC_INFO k524_fi[] = { + MAKE_FUNC_INFO(krb524_init_ets), + MAKE_FUNC_INFO(krb524_convert_creds_kdc), + 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), +#ifdef USE_MS2MIT + MAKE_FUNC_INFO(LsaNtStatusToWinError), +#endif /* USE_MS2MIT */ + END_FUNC_INFO +}; + +#ifdef USE_MS2MIT +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 +}; +#endif /* USE_MS2MIT */ + +FUNC_INFO afst_fi[] = { + MAKE_FUNC_INFO(ktc_ListTokens), + MAKE_FUNC_INFO(ktc_GetToken), + MAKE_FUNC_INFO(ktc_SetToken), + MAKE_FUNC_INFO(ktc_ForgetAllTokens), + END_FUNC_INFO +}; + +FUNC_INFO afsc_fi[] = { + MAKE_FUNC_INFO(cm_SearchCellFile), + MAKE_FUNC_INFO(cm_GetRootCellName), + END_FUNC_INFO +}; + +/* Static Prototypes */ +char *afs_realm_of_cell(struct afsconf_cell *); +static long get_cellconfig_callback(void *, struct sockaddr_in *, char *); +int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *); +static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context, + void *data, const char *name, const char *banner, int num_prompts, + krb5_prompt prompts[]); + + +/* Static Declarations */ +static int inited = 0; +static int mid_cnt = 0; +static struct textField * mid_tb = NULL; +static HINSTANCE hKrb5 = 0; +static HINSTANCE hKrb4 = 0; +static HINSTANCE hKrb524 = 0; +#ifdef USE_MS2MIT +static HINSTANCE hSecur32 = 0; +#endif /* USE_MS2MIT */ +static HINSTANCE hAdvApi32 = 0; +static HINSTANCE hAfsTokens = 0; +static HINSTANCE hAfsConf = 0; +static HINSTANCE hComErr = 0; +static HINSTANCE hService = 0; +static HINSTANCE hProfile = 0; +static HINSTANCE hLeash = 0; +static HINSTANCE hCCAPI = 0; +static struct principal_ccache_data * princ_cc_data = NULL; +static struct cell_principal_map * cell_princ_map = NULL; + +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(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0); + LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0); + LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0); +#ifdef USE_MS2MIT + LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1); +#endif /* USE_MS2MIT */ + LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1); + LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); + LoadFuncs(AFSTOKENS_DLL, afst_fi, &hAfsTokens, 0, 1, 0, 0); + LoadFuncs(AFSCONF_DLL, afsc_fi, &hAfsConf, 0, 1, 0, 0); + LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0); + LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); + + if ( KFW_is_available() ) { + char rootcell[MAXCELLCHARS+1]; +#ifdef USE_MS2MIT + KFW_import_windows_lsa(); +#endif /* USE_MS2MIT */ + KFW_import_ccache_data(); + KFW_AFS_renew_expiring_tokens(); + + /* WIN32 NOTE: no way to get max chars */ + if (!pcm_GetRootCellName(rootcell)) + KFW_AFS_renew_token_for_cell(rootcell); + } + } + ReleaseMutex(hMutex); + CloseHandle(hMutex); + } +} + +void +KFW_cleanup(void) +{ + if (hKrb5) + FreeLibrary(hKrb5); + if (hKrb4) + FreeLibrary(hKrb4); + if (hProfile) + FreeLibrary(hProfile); + if (hAfsTokens) + FreeLibrary(hAfsTokens); + if (hAfsConf) + FreeLibrary(hAfsConf); + if (hComErr) + FreeLibrary(hComErr); + if (hService) + FreeLibrary(hService); +#ifdef USE_MS2MIT + if (hSecur32) + FreeLibrary(hSecur32); +#endif /* USE_MS2MIT */ + if (hKrb524) + FreeLibrary(hKrb524); + if (hLeash) + FreeLibrary(hLeash); + if (hCCAPI) + FreeLibrary(hCCAPI); +} + +static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client"; + +int +KFW_is_available(void) +{ + HKEY parmKey; + DWORD code, len; + DWORD enableKFW = 1; + + code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName, + 0, KEY_QUERY_VALUE, &parmKey); + if (code != ERROR_SUCCESS) + code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName, + 0, KEY_QUERY_VALUE, &parmKey); + if (code == ERROR_SUCCESS) { + len = sizeof(enableKFW); + code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL, + (BYTE *) &enableKFW, &len); + if (code != ERROR_SUCCESS) { + enableKFW = 1; + } + RegCloseKey (parmKey); + } + + if ( !enableKFW ) + return FALSE; + + KFW_initialize(); + if ( hKrb5 && hComErr && hService && +#ifdef USE_MS2MIT + hSecur32 && +#endif /* USE_MS2MIT */ + hKrb524 && + hProfile && hAfsTokens && hAfsConf && hLeash && hCCAPI ) + return TRUE; + return FALSE; +} + +int +KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName, + int FreeContextFlag, krb5_context * ctx, + krb5_ccache * cache) +{ + char message[256]; + const char *errText; + int krb5Error = ((int)(rc & 255)); + + /* + switch (krb5Error) + { + // Wrong password + case 31: + case 8: + return; + } + */ + + errText = perror_message(rc); + _snprintf(message, sizeof(message), + "%s\n(Kerberos error %ld)\n\n%s failed", + errText, + krb5Error, + FailedFunctionName); + + if ( IsDebuggerPresent() ) + OutputDebugString(message); + + MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | + MB_TASKMODAL | + MB_SETFOREGROUND); + if (FreeContextFlag == 1) + { + if (ctx && *ctx != NULL) + { + if (cache && *cache != NULL) { + pkrb5_cc_close(*ctx, *cache); + *cache = NULL; + } + + pkrb5_free_context(*ctx); + *ctx = NULL; + } + } + + return rc; +} + +void +KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa) +{ + struct principal_ccache_data * next = princ_cc_data; + krb5_principal principal = 0; + char * pname = NULL; + const char * ccname = NULL; + krb5_error_code code = 0; + krb5_error_code cc_code = 0; + krb5_cc_cursor cur; + krb5_creds creds; + krb5_flags flags=0; + krb5_timestamp now; + + if (ctx == 0 || cc == 0) + return; + + code = pkrb5_cc_get_principal(ctx, cc, &principal); + if ( code ) return; + + code = pkrb5_unparse_name(ctx, principal, &pname); + if ( code ) goto cleanup; + + ccname = pkrb5_cc_get_name(ctx, cc); + if (!ccname) goto cleanup; + + // Search the existing list to see if we have a match + if ( next ) { + for ( ; next ; next = next->next ) { + if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) ) + break; + } + } + + // If not, match add a new node to the beginning of the list and assign init it + if ( !next ) { + next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data)); + next->next = princ_cc_data; + princ_cc_data = next; + next->principal = _strdup(pname); + next->ccache_name = _strdup(ccname); + next->from_lsa = lsa; + next->expired = 1; + next->expiration_time = 0; + next->renew = 0; + } + + flags = 0; // turn off OPENCLOSE mode + code = pkrb5_cc_set_flags(ctx, cc, flags); + if ( code ) goto cleanup; + + code = pkrb5_timeofday(ctx, &now); + + cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur); + + while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) { + if ( creds.ticket_flags & TKT_FLG_INITIAL ) { + int valid; + // we found the ticket we are looking for + // check validity of timestamp + // We add a 5 minutes fudge factor to compensate for potential + // clock skew errors between the KDC and client OS + + valid = ((creds.times.starttime > 0) && + now >= (creds.times.starttime - 300) && + now < (creds.times.endtime + 300) && + !(creds.ticket_flags & TKT_FLG_INVALID)); + + if ( next->from_lsa) { + next->expired = 0; + next->expiration_time = creds.times.endtime; + next->renew = 1; + } else if ( valid ) { + next->expired = 0; + next->expiration_time = creds.times.endtime; + next->renew = (creds.times.renew_till > creds.times.endtime) && + (creds.ticket_flags & TKT_FLG_RENEWABLE); + } else { + next->expired = 1; + next->expiration_time = 0; + next->renew = 0; + } + + pkrb5_free_cred_contents(ctx, &creds); + cc_code = KRB5_CC_END; + break; + } + pkrb5_free_cred_contents(ctx, &creds); + } + + if (cc_code == KRB5_CC_END) { + code = pkrb5_cc_end_seq_get(ctx, cc, &cur); + if (code) goto cleanup; + } + + cleanup: + flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE + code = pkrb5_cc_set_flags(ctx, cc, flags); + + if ( pname ) + pkrb5_free_unparsed_name(ctx,pname); + if ( principal ) + pkrb5_free_principal(ctx,principal); +} + +int +KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only) +{ + struct principal_ccache_data * next = princ_cc_data; + char * response = NULL; + + if ( !principal || !ccache ) + return 0; + + while ( next ) { + if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) { + if (response) { + // we always want to prefer the MS Kerberos LSA cache or + // the cache afscreds created specifically for the principal + // if the current entry is either one, drop the previous find + if ( next->from_lsa || !strcmp(next->ccache_name,principal) ) + free(response); + } + response = _strdup(next->ccache_name); + // MS Kerberos LSA is our best option so use it and quit + if ( next->from_lsa ) + break; + } + next = next->next; + } + + if ( response ) { + *ccache = response; + return 1; + } + return 0; +} + +void +KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname) +{ + struct principal_ccache_data ** next = &princ_cc_data; + + if ( !pname && !ccname ) + return; + + while ( (*next) ) { + if ( !strcmp((*next)->principal,pname) || + !strcmp((*next)->ccache_name,ccname) ) { + void * temp; + free((*next)->principal); + free((*next)->ccache_name); + temp = (*next); + (*next) = (*next)->next; + free(temp); + } + } +} + +void +KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active) +{ + struct cell_principal_map * next = cell_princ_map; + + // Search the existing list to see if we have a match + if ( next ) { + for ( ; next ; next = next->next ) { + if ( !strcmp(next->cell, cell) ) { + if ( !strcmp(next->principal,pname) ) { + next->active = active; + break; + } else { + // OpenAFS currently has a restriction of one active token per cell + // Therefore, whenever we update the table with a new active cell we + // must mark all of the other principal to cell entries as inactive. + if (active) + next->active = 0; + } + } + } + } + + // If not, match add a new node to the beginning of the list and assign init it + if ( !next ) { + next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map)); + next->next = cell_princ_map; + cell_princ_map = next; + next->principal = _strdup(pname); + next->cell = _strdup(cell); + next->active = active; + } +} + +void +KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell) +{ + struct cell_principal_map ** next = &cell_princ_map; + + if ( !pname && !cell ) + return; + + while ( (*next) ) { + if ( !strcmp((*next)->principal,pname) || + !strcmp((*next)->cell,cell) ) { + void * temp; + free((*next)->principal); + free((*next)->cell); + temp = (*next); + (*next) = (*next)->next; + free(temp); + } + } +} + +// Returns (if possible) a principal which has been known in +// the past to have been used to obtain tokens for the specified +// cell. +// TODO: Attempt to return one which has not yet expired by checking +// the principal/ccache data +int +KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only) +{ + struct cell_principal_map * next_map = cell_princ_map; + const char * princ = NULL; + int count = 0, i; + + if ( !cell ) + return 0; + + while ( next_map ) { + if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) { + count++; + } + next_map = next_map->next; + } + + if ( !principals || !count ) + return count; + + *principals = (char **) malloc(sizeof(char *) * count); + for ( next_map = cell_princ_map, i=0 ; next_map && inext ) + { + if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) { + (*principals)[i++] = _strdup(next_map->principal); + } + } + return count; +} + +int +KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only) +{ + int count = 0, i; + struct cell_principal_map * next_map = cell_princ_map; + const char * princ = NULL; + + if ( !pname ) + return 0; + + while ( next_map ) { + if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) { + count++; + } + next_map = next_map->next; + } + + if ( !cells ) + return count; + + *cells = (char **) malloc(sizeof(char *) * count); + for ( next_map = cell_princ_map, i=0 ; next_map && inext ) + { + if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) { + (*cells)[i++] = _strdup(next_map->cell); + } + } + return count; +} + +/* Given a principal return an existing ccache or create one and return */ +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; + + if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) && + !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) { + ccname = (char *)malloc(strlen(pname) + 5); + sprintf(ccname,"API:%s",pname); + } + 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); +} + +#ifdef USE_MS2MIT +// Import Microsoft Credentials into a new MIT ccache +void +KFW_import_windows_lsa(void) +{ + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_principal princ = 0; + char * pname = NULL; + krb5_data * realm; + krb5_error_code code; + char cell[128]=""; + int i; + + if (!pkrb5_init_context) + return; + +#ifdef COMMENT + if ( !MSLSA_IsKerberosLogon() ) + return; +#endif + + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + + code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc); + if (code) goto cleanup; + + KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE); + + code = pkrb5_cc_get_principal(ctx, cc, &princ); + if ( code ) goto cleanup; + + code = pkrb5_unparse_name(ctx,princ,&pname); + if ( code ) goto cleanup; + + realm = krb5_princ_realm(ctx, princ); + for ( i=0; ilength; i++ ) { + cell[i] = tolower(realm->data[i]); + } + cell[i] = '\0'; + + code = KFW_AFS_klog(ctx, cc, "afs", cell, realm->data, pLeash_get_default_lifetime(),NULL); + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"KFW_AFS_klog() returns: %d\n",code); + OutputDebugString(message); + } + if ( code ) goto cleanup; + + KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE); + + cleanup: + if (pname) + pkrb5_free_unparsed_name(ctx,pname); + if (princ) + pkrb5_free_principal(ctx,princ); + if (cc) + pkrb5_cc_close(ctx,cc); + if (ctx) + pkrb5_free_context(ctx); +} +#endif /* USE_MS2MIT */ + +// If there are existing MIT credentials, copy them to a new +// ccache named after the principal + +// Enumerate all existing MIT ccaches and construct entries +// in the principal_ccache table + +// Enumerate all existing AFS Tokens and construct entries +// in the cell_principal table +void +KFW_import_ccache_data(void) +{ + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_principal principal = 0; + krb5_creds creds; + krb5_error_code code; + krb5_error_code cc_code; + krb5_cc_cursor cur; + apiCB * cc_ctx = 0; + struct _infoNC ** pNCi = NULL; + int i, j, flags; + + if ( !pcc_initialize ) + return; + + if ( IsDebuggerPresent() ) + OutputDebugString("KFW_import_ccache_data()\n"); + + code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); + if (code) goto cleanup; + + code = pcc_get_NC_info(cc_ctx, &pNCi); + if (code) goto cleanup; + + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + + for ( i=0; pNCi[i]; i++ ) { + if ( pNCi[i]->vers != CC_CRED_V5 ) + continue; + if ( IsDebuggerPresent() ) { + OutputDebugString("Principal: "); + OutputDebugString(pNCi[i]->principal); + OutputDebugString(" in ccache "); + OutputDebugString(pNCi[i]->name); + OutputDebugString("\n"); + } + if ( strcmp(pNCi[i]->name,pNCi[i]->principal) + && strcmp(pNCi[i]->name,LSA_CCNAME) + ) { + int found = 0; + for ( j=0; pNCi[j]; j++ ) { + if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) { + found = 1; + break; + } + } + + code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc); + if (code) goto loop_cleanup; + + if (!found) { + krb5_ccache oldcc = 0; + + if ( IsDebuggerPresent() ) + OutputDebugString("copying ccache data to new ccache\n"); + + code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal); + if (code) goto loop_cleanup; + code = pkrb5_cc_initialize(ctx, cc, principal); + if (code) goto loop_cleanup; + + code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc); + if (code) goto loop_cleanup; + code = pkrb5_cc_copy_creds(ctx,oldcc,cc); + if (code) { + code = pkrb5_cc_close(ctx,cc); + cc = 0; + code = pkrb5_cc_close(ctx,oldcc); + cc = 0; + KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL); + continue; + } + code = pkrb5_cc_close(ctx,oldcc); + } + } else { + code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc); + if (code) goto loop_cleanup; + } + + flags = 0; // turn off OPENCLOSE mode + code = pkrb5_cc_set_flags(ctx, cc, flags); + if ( code ) goto cleanup; + + KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME)); + + cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur); + + while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) { + krb5_data * sname = krb5_princ_name(ctx, creds.server); + krb5_data * cell = krb5_princ_component(ctx, creds.server, 1); + krb5_data * realm = krb5_princ_realm(ctx, creds.server); + if ( sname && cell && !strcmp("afs",sname->data) ) { + struct ktc_principal aserver; + struct ktc_principal aclient; + struct ktc_token atoken; + int active = TRUE; + + if ( IsDebuggerPresent() ) { + OutputDebugString("Found AFS ticket: "); + OutputDebugString(sname->data); + if ( cell->data ) { + OutputDebugString("/"); + OutputDebugString(cell->data); + } + OutputDebugString("@"); + OutputDebugString(realm->data); + OutputDebugString("\n"); + } + + memset(&aserver, '\0', sizeof(aserver)); + strcpy(aserver.name, sname->data); + strcpy(aserver.cell, cell->data); + + code = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient); + if (!code) { + // Found a token in AFS Client Server which matches + char pname[128], *p, *q; + for ( p=pname, q=aclient.name; *q; p++, q++) + *p = *q; + for ( *p++ = '@', q=aclient.cell; *q; p++, q++) + *p = toupper(*q); + *p = '\0'; + + if ( IsDebuggerPresent() ) { + OutputDebugString("Found AFS token: "); + OutputDebugString(pname); + OutputDebugString("\n"); + } + + if ( strcmp(pname,pNCi[i]->principal) ) + active = FALSE; + KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active); + } else { + // Attempt to import it + KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active); + + if ( IsDebuggerPresent() ) { + OutputDebugString("Calling KFW_AFS_klog() to obtain token\n"); + } + + code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime(),NULL); + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"KFW_AFS_klog() returns: %d\n",code); + OutputDebugString(message); + } + } + } else if ( IsDebuggerPresent() ) { + OutputDebugString("Found ticket: "); + OutputDebugString(sname->data); + if ( cell && cell->data ) { + OutputDebugString("/"); + OutputDebugString(cell->data); + } + OutputDebugString("@"); + OutputDebugString(realm->data); + OutputDebugString("\n"); + } + pkrb5_free_cred_contents(ctx, &creds); + } + + if (cc_code == KRB5_CC_END) { + cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur); + if (cc_code) goto loop_cleanup; + } + + loop_cleanup: + flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE + code = pkrb5_cc_set_flags(ctx, cc, flags); + if (cc) { + pkrb5_cc_close(ctx,cc); + cc = 0; + } + if (principal) { + pkrb5_free_principal(ctx,principal); + principal = 0; + } + } + + cleanup: + if (ctx) + pkrb5_free_context(ctx); + if (pNCi) + pcc_free_NC_info(cc_ctx, &pNCi); + if (cc_ctx) + pcc_shutdown(&cc_ctx); +} + + +int +KFW_AFS_get_cred(char * username, + char * instance, + char * cell, + char * password, + int lifetime, + char * smbname, + char ** reasonP ) +{ + krb5_context ctx = 0; + krb5_ccache cc = 0; + char * realm = 0; + char ** realmlist = 0; + krb5_principal principal = 0; + char * pname = 0; + krb5_error_code code; + char local_cell[MAXCELLCHARS+1]; + char **cells = NULL; + int cell_count=0; + struct afsconf_cell cellconfig; + + if (!pkrb5_init_context) + return 0; + + if ( IsDebuggerPresent() ) { + OutputDebugString("KFW_AFS_get_cred for token "); + OutputDebugString(username); + if ( instance ) { + OutputDebugString("/"); + OutputDebugString(instance); + } + OutputDebugString("@"); + OutputDebugString(cell); + OutputDebugString("\n"); + } + + code = pkrb5_init_context(&ctx); + if ( code ) goto cleanup; + + code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell); + if ( code ) goto cleanup; + + realm = strchr(username,'@'); + if (realm) { + *realm = '\0'; + realm++; + } + if ( !realm || !realm[0] ) + realm = afs_realm_of_cell(&cellconfig); // do not free + + if ( IsDebuggerPresent() ) { + OutputDebugString("Realm: "); + OutputDebugString(realm); + OutputDebugString("\n"); + } + + code = pkrb5_build_principal(ctx, &principal, strlen(realm), + realm, username, + (instance && instance[0]) ? instance : NULL, + NULL); + + code = KFW_get_ccache(ctx, principal, &cc); + if ( code ) goto cleanup; + + code = pkrb5_unparse_name(ctx, principal, &pname); + if ( code ) goto cleanup; + + if ( lifetime == 0 ) + lifetime = pLeash_get_default_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()); + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"KFW_kinit() returns: %d\n",code); + OutputDebugString(message); + } + if ( code ) goto cleanup; + + KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE); + + code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime,smbname); + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"KFW_AFS_klog() returns: %d\n",code); + OutputDebugString(message); + } + if ( code ) goto cleanup; + + KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE); + + // Attempt to obtain new tokens for other cells supported by the same + // principal + cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE); + if ( cell_count > 1 ) { + while ( cell_count-- ) { + if ( strcmp(cells[cell_count],cell) ) { + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"found another cell for the same principal: %s\n",cell); + OutputDebugString(message); + } + code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell); + if ( code ) continue; + + realm = afs_realm_of_cell(&cellconfig); // do not free + if ( IsDebuggerPresent() ) { + OutputDebugString("Realm: "); + OutputDebugString(realm); + OutputDebugString("\n"); + } + + code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime,smbname); + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"KFW_AFS_klog() returns: %d\n",code); + OutputDebugString(message); + } + } + free(cells[cell_count]); + } + free(cells); + } else if ( cell_count == 1 ) { + free(cells[0]); + free(cells); + } + + cleanup: + if ( pname ) + pkrb5_free_unparsed_name(ctx,pname); + if ( cc ) + pkrb5_cc_close(ctx, cc); + + if ( code && reasonP ) { + *reasonP = (char *)perror_message(code); + } + return(code); +} + +int +KFW_AFS_destroy_tickets_for_cell(char * cell) +{ + krb5_context ctx = 0; + krb5_error_code code; + int count; + char ** principals = NULL; + + if (!pkrb5_init_context) + return 0; + + if ( IsDebuggerPresent() ) { + OutputDebugString("KFW_AFS_destroy_ticets_for_cell: "); + OutputDebugString(cell); + OutputDebugString("\n"); + } + + code = pkrb5_init_context(&ctx); + if (code) ctx = 0; + + count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE); + if ( count > 0 ) { + krb5_principal princ = 0; + krb5_ccache cc = 0; + + while ( count-- ) { + int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE); + if ( cell_count > 1 ) { + // TODO - What we really should do here is verify whether or not any of the + // other cells which use this principal to obtain its credentials actually + // have valid tokens or not. If they are currently using these credentials + // we will skip them. For the time being we assume that if there is an active + // map in the table that they are actively being used. + goto loop_cleanup; + } + + code = pkrb5_parse_name(ctx, principals[count], &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; + } + + KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE); + free(principals[count]); + } + free(principals); + } + pkrb5_free_context(ctx); + return 0; +} + +int +KFW_AFS_renew_expiring_tokens(void) +{ + krb5_error_code code = 0; + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_timestamp now; + struct principal_ccache_data * pcc_next = princ_cc_data; + int cell_count; + char ** cells=NULL; + const char * realm = NULL; + char local_cell[MAXCELLCHARS+1]=""; + struct afsconf_cell cellconfig; + + if (!pkrb5_init_context) + return 0; + + if ( pcc_next == NULL ) // nothing to do + return 0; + + if ( IsDebuggerPresent() ) { + OutputDebugString("KFW_AFS_renew_expiring_tokens\n"); + } + + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + + code = pkrb5_timeofday(ctx, &now); + if (code) goto cleanup; + + for ( ; pcc_next ; pcc_next = pcc_next->next ) { + if ( pcc_next->expired ) + continue; + + if ( now >= (pcc_next->expiration_time) ) { + if ( !pcc_next->from_lsa ) { + pcc_next->expired = 1; + continue; + } + } + + if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) { + code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc); + if ( code ) + goto loop_cleanup; + code = KFW_renew(ctx,cc); +#ifdef USE_MS2MIT + if ( code && pcc_next->from_lsa) + goto loop_cleanup; +#endif /* USE_MS2MIT */ + + + KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa); + if (code) goto loop_cleanup; + + // Attempt to obtain new tokens for other cells supported by the same + // principal + cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE); + if ( cell_count > 0 ) { + while ( cell_count-- ) { + if ( IsDebuggerPresent() ) { + OutputDebugString("Cell: "); + OutputDebugString(cells[cell_count]); + OutputDebugString("\n"); + } + code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell); + if ( code ) continue; + realm = afs_realm_of_cell(&cellconfig); // do not free + if ( IsDebuggerPresent() ) { + OutputDebugString("Realm: "); + OutputDebugString(realm); + OutputDebugString("\n"); + } + code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, pLeash_get_default_lifetime(),NULL); + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"KFW_AFS_klog() returns: %d\n",code); + OutputDebugString(message); + } + free(cells[cell_count]); + } + free(cells); + } + } + + loop_cleanup: + if ( cc ) { + pkrb5_cc_close(ctx,cc); + cc = 0; + } + } + + cleanup: + if ( cc ) + pkrb5_cc_close(ctx,cc); + if ( ctx ) + pkrb5_free_context(ctx); + + return 0; +} + + +BOOL +KFW_AFS_renew_token_for_cell(char * cell) +{ + krb5_error_code code = 0; + krb5_context ctx = 0; + int count; + char ** principals = NULL; + + if (!pkrb5_init_context) + return 0; + + if ( IsDebuggerPresent() ) { + OutputDebugString("KFW_AFS_renew_token_for_cell:"); + OutputDebugString(cell); + OutputDebugString("\n"); + } + + code = pkrb5_init_context(&ctx); + if (code) goto cleanup; + + count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE); + if ( count == 0 ) { + // We know we must have a credential somewhere since we are + // trying to renew a token + + KFW_import_ccache_data(); + count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE); + } + if ( count > 0 ) { + krb5_principal princ = 0; + krb5_principal service = 0; +#ifdef COMMENT + krb5_creds mcreds, creds; +#endif /* COMMENT */ + krb5_ccache cc = 0; + const char * realm = NULL; + struct afsconf_cell cellconfig; + char local_cell[MAXCELLCHARS+1]; + + while ( count-- ) { + code = pkrb5_parse_name(ctx, principals[count], &princ); + if (code) goto loop_cleanup; + + code = KFW_get_ccache(ctx, princ, &cc); + if (code) goto loop_cleanup; + + code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell); + if ( code ) goto loop_cleanup; + + realm = afs_realm_of_cell(&cellconfig); // do not free + if ( IsDebuggerPresent() ) { + OutputDebugString("Realm: "); + OutputDebugString(realm); + OutputDebugString("\n"); + } + +#ifdef COMMENT + /* krb5_cc_remove_cred() is not implemented + * for a single cred + */ + code = pkrb5_build_principal(ctx, &service, strlen(realm), + realm, "afs", cell, NULL); + if (!code) { + memset(&mcreds, 0, sizeof(krb5_creds)); + mcreds.client = princ; + mcreds.server = service; + + code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds); + if (!code) { + if ( IsDebuggerPresent() ) { + char * cname, *sname; + pkrb5_unparse_name(ctx, creds.client, &cname); + pkrb5_unparse_name(ctx, creds.server, &sname); + OutputDebugString("Removing credential for client \""); + OutputDebugString(cname); + OutputDebugString("\" and service \""); + OutputDebugString(sname); + OutputDebugString("\"\n"); + pkrb5_free_unparsed_name(ctx,cname); + pkrb5_free_unparsed_name(ctx,sname); + } + + code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds); + pkrb5_free_principal(ctx, creds.client); + pkrb5_free_principal(ctx, creds.server); + } + } +#endif /* COMMENT */ + + code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, pLeash_get_default_lifetime(),NULL); + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"KFW_AFS_klog() returns: %d\n",code); + OutputDebugString(message); + } + + loop_cleanup: + if (cc) { + pkrb5_cc_close(ctx, cc); + cc = 0; + } + if (princ) { + pkrb5_free_principal(ctx, princ); + princ = 0; + } + if (service) { + pkrb5_free_principal(ctx, service); + princ = 0; + } + + KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE); + free(principals[count]); + } + free(principals); + } else + code = -1; // we did not renew the tokens + + cleanup: + pkrb5_free_context(ctx); + return (code ? FALSE : TRUE); + +} + +int +KFW_AFS_renew_tokens_for_all_cells(void) +{ + struct cell_principal_map * next = cell_princ_map; + + if ( IsDebuggerPresent() ) + OutputDebugString("KFW_AFS_renew_tokens_for_all()\n"); + + if ( !next ) + return 0; + + for ( ; next ; next = next->next ) { + if ( next->active ) + KFW_AFS_renew_token_for_cell(next->cell); + } + return 0; +} + +int +KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc) +{ + krb5_error_code code = 0; + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_principal me = 0; + krb5_principal server = 0; + krb5_creds my_creds; + krb5_data *realm = 0; + + if (!pkrb5_init_context) + return 0; + + memset(&my_creds, 0, sizeof(krb5_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_cc_get_principal(ctx, cc, &me); + if (code) goto cleanup; + + realm = krb5_princ_realm(ctx, me); + + code = pkrb5_build_principal_ext(ctx, &server, + realm->length,realm->data, + KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, + realm->length,realm->data, + 0); + if ( code ) + goto cleanup; + + if ( IsDebuggerPresent() ) { + char * cname, *sname; + pkrb5_unparse_name(ctx, me, &cname); + pkrb5_unparse_name(ctx, server, &sname); + OutputDebugString("Renewing credential for client \""); + OutputDebugString(cname); + OutputDebugString("\" and service \""); + OutputDebugString(sname); + OutputDebugString("\"\n"); + pkrb5_free_unparsed_name(ctx,cname); + pkrb5_free_unparsed_name(ctx,sname); + } + + my_creds.client = me; + my_creds.server = server; + + code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL); + if (code) { + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code); + OutputDebugString(message); + } + goto cleanup; + } + + code = pkrb5_cc_initialize(ctx, cc, me); + if (code) { + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"krb5_cc_initialize() failed: %d\n",code); + OutputDebugString(message); + } + goto cleanup; + } + + code = pkrb5_cc_store_cred(ctx, cc, &my_creds); + if (code) { + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"krb5_cc_store_cred() failed: %d\n",code); + OutputDebugString(message); + } + goto cleanup; + } + + cleanup: + if (my_creds.client == me) + my_creds.client = 0; + if (my_creds.server == server) + my_creds.server = 0; + pkrb5_free_cred_contents(ctx, &my_creds); + if (me) + pkrb5_free_principal(ctx, me); + if (server) + pkrb5_free_principal(ctx, server); + if (cc && (cc != alt_cc)) + pkrb5_cc_close(ctx, cc); + 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(); + else + lifetime *= 5*60; + + if (renew_life > 0) + renew_life *= 5*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) + { + // we are going to add the public IP address specified by the user + // to the list provided by the operating system + 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); /* safe */ + 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, // password + KRB5_prompter, // prompter + hParent, // prompter data + 0, // start time + 0, // service name + &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;icontents ) + 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_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc) +{ + krb5_context ctx; + krb5_ccache cc; + 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 ( alt_cc ) { + cc = alt_cc; + } else { + code = pkrb5_cc_default(ctx, &cc); + if (code) goto cleanup; + } + + code = pkrb5_cc_destroy(ctx, cc); + if ( !code ) cc = 0; + + cleanup: + if (cc && (cc != alt_cc)) + pkrb5_cc_close(ctx, cc); + if (ctx && (ctx != alt_ctx)) + pkrb5_free_context(ctx); + + return(code); +} + + +#ifdef USE_MS2MIT +static BOOL +GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData) +{ + NTSTATUS Status = 0; + HANDLE TokenHandle; + TOKEN_STATISTICS Stats; + DWORD ReqLen; + BOOL Success; + + if (!ppSessionData) + return FALSE; + *ppSessionData = NULL; + + Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); + if ( !Success ) + return FALSE; + + Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); + CloseHandle( TokenHandle ); + if ( !Success ) + return FALSE; + + Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); + if ( FAILED(Status) || !ppSessionData ) + return FALSE; + + return TRUE; +} + +// +// MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the +// cache. It validates whether or not it is reasonable to assume that if we +// attempted to retrieve valid tickets we could do so. Microsoft does not +// automatically renew expired tickets. Therefore, the cache could contain +// expired or invalid tickets. Microsoft also caches the user's password +// and will use it to retrieve new TGTs if the cache is empty and tickets +// are requested. + +static BOOL +MSLSA_IsKerberosLogon(VOID) +{ + PSECURITY_LOGON_SESSION_DATA pSessionData = NULL; + BOOL Success = FALSE; + + if ( GetSecurityLogonSessionData(&pSessionData) ) { + if ( pSessionData->AuthenticationPackage.Buffer ) { + WCHAR buffer[256]; + WCHAR *usBuffer; + int usLength; + + Success = FALSE; + usBuffer = (pSessionData->AuthenticationPackage).Buffer; + usLength = (pSessionData->AuthenticationPackage).Length; + if (usLength < 256) + { + lstrcpynW (buffer, usBuffer, usLength); + lstrcatW (buffer,L""); + if ( !lstrcmpW(L"Kerberos",buffer) ) + Success = TRUE; + } + } + pLsaFreeReturnBuffer(pSessionData); + } + return Success; +} +#endif /* USE_MS2MIT */ + +static BOOL CALLBACK +MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam) +{ + int i; + + switch ( message ) { + case WM_INITDIALOG: + if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT ) + { + SetFocus(GetDlgItem( hDialog, ID_MID_TEXT)); + return FALSE; + } + for ( i=0; i < mid_cnt ; i++ ) { + if (mid_tb[i].echo == 0) + SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0); + else if (mid_tb[i].echo == 2) + SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0); + } + return TRUE; + + case WM_COMMAND: + switch ( LOWORD(wParam) ) { + case IDOK: + for ( i=0; i < mid_cnt ; i++ ) { + if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) ) + *mid_tb[i].buf = '\0'; + } + /* fallthrough */ + case IDCANCEL: + EndDialog(hDialog, LOWORD(wParam)); + return TRUE; + } + } + return FALSE; +} + +static LPWORD +lpwAlign( LPWORD lpIn ) +{ + ULONG ul; + + ul = (ULONG) lpIn; + ul += 3; + ul >>=2; + ul <<=2; + return (LPWORD) ul;; +} + +/* + * dialog widths are measured in 1/4 character widths + * dialog height are measured in 1/8 character heights + */ + +static LRESULT +MultiInputDialog( HINSTANCE hinst, HWND hwndOwner, + char * ptext[], int numlines, int width, + int tb_cnt, struct textField * tb) +{ + HGLOBAL hgbl; + LPDLGTEMPLATE lpdt; + LPDLGITEMTEMPLATE lpdit; + LPWORD lpw; + LPWSTR lpwsz; + LRESULT ret; + int nchar, i, pwid; + + hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096); + if (!hgbl) + return -1; + + mid_cnt = tb_cnt; + mid_tb = tb; + + lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl); + + // Define a dialog box. + + lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU + | DS_MODALFRAME | WS_CAPTION | DS_CENTER + | DS_SETFOREGROUND | DS_3DLOOK + | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE; + lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls + lpdt->x = 10; + lpdt->y = 10; + lpdt->cx = 20 + width * 4; + lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14; + + lpw = (LPWORD) (lpdt + 1); + *lpw++ = 0; // no menu + *lpw++ = 0; // predefined dialog box class (by default) + + lpwsz = (LPWSTR) lpw; + nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128); + lpw += nchar; + *lpw++ = 8; // font size (points) + lpwsz = (LPWSTR) lpw; + nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg", + -1, lpwsz, 128); + lpw += nchar; + + //----------------------- + // Define an OK button. + //----------------------- + lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary + lpdit = (LPDLGITEMTEMPLATE) lpw; + lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER; + lpdit->dwExtendedStyle = 0; + lpdit->x = (lpdt->cx - 14)/4 - 20; + lpdit->y = 10 + (numlines + tb_cnt + 2) * 14; + lpdit->cx = 40; + lpdit->cy = 14; + lpdit->id = IDOK; // OK button identifier + + lpw = (LPWORD) (lpdit + 1); + *lpw++ = 0xFFFF; + *lpw++ = 0x0080; // button class + + lpwsz = (LPWSTR) lpw; + nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50); + lpw += nchar; + *lpw++ = 0; // no creation data + + //----------------------- + // Define an Cancel button. + //----------------------- + lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary + lpdit = (LPDLGITEMTEMPLATE) lpw; + lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER; + lpdit->dwExtendedStyle = 0; + lpdit->x = (lpdt->cx - 14)*3/4 - 20; + lpdit->y = 10 + (numlines + tb_cnt + 2) * 14; + lpdit->cx = 40; + lpdit->cy = 14; + lpdit->id = IDCANCEL; // CANCEL button identifier + + lpw = (LPWORD) (lpdit + 1); + *lpw++ = 0xFFFF; + *lpw++ = 0x0080; // button class + + lpwsz = (LPWSTR) lpw; + nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50); + lpw += nchar; + *lpw++ = 0; // no creation data + + /* Add controls for preface data */ + for ( i=0; istyle = WS_CHILD | WS_VISIBLE | SS_LEFT; + lpdit->dwExtendedStyle = 0; + lpdit->x = 10; + lpdit->y = 10 + i * 14; + lpdit->cx = strlen(ptext[i]) * 4 + 10; + lpdit->cy = 14; + lpdit->id = ID_TEXT + i; // text identifier + + lpw = (LPWORD) (lpdit + 1); + *lpw++ = 0xFFFF; + *lpw++ = 0x0082; // static class + + lpwsz = (LPWSTR) lpw; + nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i], + -1, lpwsz, 2*width); + lpw += nchar; + *lpw++ = 0; // no creation data + } + + for ( i=0, pwid = 0; istyle = WS_CHILD | WS_VISIBLE | SS_LEFT; + lpdit->dwExtendedStyle = 0; + lpdit->x = 10; + lpdit->y = 10 + (numlines + i + 1) * 14; + lpdit->cx = pwid * 4; + lpdit->cy = 14; + lpdit->id = ID_TEXT + numlines + i; // text identifier + + lpw = (LPWORD) (lpdit + 1); + *lpw++ = 0xFFFF; + *lpw++ = 0x0082; // static class + + lpwsz = (LPWSTR) lpw; + nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "", + -1, lpwsz, 128); + lpw += nchar; + *lpw++ = 0; // no creation data + + /*----------------------- + * Define an edit control. + *-----------------------*/ + lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */ + lpdit = (LPDLGITEMTEMPLATE) lpw; + lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD); + lpdit->dwExtendedStyle = 0; + lpdit->x = 10 + (pwid + 1) * 4; + lpdit->y = 10 + (numlines + i + 1) * 14; + lpdit->cx = (width - (pwid + 1)) * 4; + lpdit->cy = 14; + lpdit->id = ID_MID_TEXT + i; // identifier + + lpw = (LPWORD) (lpdit + 1); + *lpw++ = 0xFFFF; + *lpw++ = 0x0081; // edit class + + lpwsz = (LPWSTR) lpw; + nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "", + -1, lpwsz, 128); + lpw += nchar; + *lpw++ = 0; // no creation data + } + + GlobalUnlock(hgbl); + ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, + hwndOwner, (DLGPROC) MultiInputDialogProc); + GlobalFree(hgbl); + + switch ( ret ) { + case 0: /* Timeout */ + return -1; + case IDOK: + return 1; + case IDCANCEL: + return 0; + default: { + char buf[256]; + sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError()); + MessageBox(hwndOwner, + buf, + "GetLastError()", + MB_OK | MB_ICONINFORMATION | MB_TASKMODAL); + return -1; + } + } +} + +static int +multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[]) +{ + HINSTANCE hInst = 0; + int maxwidth = 0; + int numlines = 0; + int len; + char * plines[16], *p = preface ? preface : ""; + int i; + + for ( i=0; i<16; i++ ) + plines[i] = NULL; + + while (*p && numlines < 16) { + plines[numlines++] = p; + for ( ;*p && *p != '\r' && *p != '\n'; p++ ); + if ( *p == '\r' && *(p+1) == '\n' ) { + *p++ = '\0'; + p++; + } else if ( *p == '\n' ) { + *p++ = '\0'; + } + if ( strlen(plines[numlines-1]) > maxwidth ) + maxwidth = strlen(plines[numlines-1]); + } + + for ( i=0;i 40 ? 40 : tb[i].len); + if ( maxwidth < len ) + maxwidth = len; + } + + return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)); +} + +static krb5_error_code KRB5_CALLCONV +KRB5_prompter( krb5_context context, + void *data, + const char *name, + const char *banner, + int num_prompts, + krb5_prompt prompts[]) +{ + krb5_error_code errcode = 0; + int i; + struct textField * tb = NULL; + int len = 0, blen=0, nlen=0; + HWND hParent = (HWND)data; + + if (name) + nlen = strlen(name)+2; + + if (banner) + blen = strlen(banner)+2; + + tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts); + if ( tb != NULL ) { + int ok; + memset(tb,0,sizeof(struct textField) * num_prompts); + for ( i=0; i < num_prompts; i++ ) { + tb[i].buf = prompts[i].reply->data; + tb[i].len = prompts[i].reply->length; + tb[i].label = prompts[i].prompt; + tb[i].def = NULL; + tb[i].echo = (prompts[i].hidden ? 2 : 1); + } + + ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb); + if ( ok ) { + for ( i=0; i < num_prompts; i++ ) + prompts[i].reply->length = strlen(prompts[i].reply->data); + } else + errcode = -2; + } + + if ( tb ) + free(tb); + if (errcode) { + for (i = 0; i < num_prompts; i++) { + memset(prompts[i].reply->data, 0, prompts[i].reply->length); + } + } + return errcode; +} + +BOOL +KFW_AFS_wait_for_service_start(void) +{ + char HostName[64]; + DWORD CurrentState; + + CurrentState = SERVICE_START_PENDING; + memset(HostName, '\0', sizeof(HostName)); + gethostname(HostName, sizeof(HostName)); + + while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED) + { + if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) + return(0); + if ( IsDebuggerPresent() ) { + switch ( CurrentState ) { + case SERVICE_STOPPED: + OutputDebugString("SERVICE_STOPPED\n"); + break; + case SERVICE_START_PENDING: + OutputDebugString("SERVICE_START_PENDING\n"); + break; + case SERVICE_STOP_PENDING: + OutputDebugString("SERVICE_STOP_PENDING\n"); + break; + case SERVICE_RUNNING: + OutputDebugString("SERVICE_RUNNING\n"); + break; + case SERVICE_CONTINUE_PENDING: + OutputDebugString("SERVICE_CONTINUE_PENDING\n"); + break; + case SERVICE_PAUSE_PENDING: + OutputDebugString("SERVICE_PAUSE_PENDING\n"); + break; + case SERVICE_PAUSED: + OutputDebugString("SERVICE_PAUSED\n"); + break; + default: + OutputDebugString("UNKNOWN Service State\n"); + } + } + if (CurrentState == SERVICE_STOPPED) + return(0); + if (CurrentState == SERVICE_RUNNING) + return(1); + Sleep(500); + } + return(0); +} + + +int +KFW_AFS_unlog(void) +{ + long rc; + char HostName[64]; + DWORD CurrentState; + + CurrentState = 0; + memset(HostName, '\0', sizeof(HostName)); + gethostname(HostName, sizeof(HostName)); + if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) + return(0); + if (CurrentState != SERVICE_RUNNING) + return(0); + + rc = pktc_ForgetAllTokens(); + + return(0); +} + +int +KFW_AFS_klog( + krb5_context alt_ctx, + krb5_ccache alt_cc, + char *service, + char *cell, + char *realm, + int LifeTime, + char *smbname + ) +{ + long rc = 0; + CREDENTIALS creds; + KTEXT_ST ticket; + struct ktc_principal aserver; + struct ktc_principal aclient; + char realm_of_user[REALM_SZ]; /* Kerberos realm of user */ + char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */ + char local_cell[MAXCELLCHARS+1]; + char Dmycell[MAXCELLCHARS+1]; + struct ktc_token atoken; + struct ktc_token btoken; + struct afsconf_cell ak_cellconfig; /* General information about the cell */ + char RealmName[128]; + char CellName[128]; + char ServiceName[128]; + DWORD CurrentState; + char HostName[64]; + BOOL try_krb5 = 0; + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_creds increds; + krb5_creds * k5creds = 0; + krb5_error_code code; + krb5_principal client_principal = 0; + char * cname = 0, *sname = 0; + int i, retry = 0; + + CurrentState = 0; + memset(HostName, '\0', sizeof(HostName)); + gethostname(HostName, sizeof(HostName)); + if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) { + if ( IsDebuggerPresent() ) + OutputDebugString("Unable to retrieve AFSD Service Status\n"); + return(-1); + } + if (CurrentState != SERVICE_RUNNING) { + if ( IsDebuggerPresent() ) + OutputDebugString("AFSD Service NOT RUNNING\n"); + return(-2); + } + + if (!pkrb5_init_context) + return 0; + + memset(RealmName, '\0', sizeof(RealmName)); + memset(CellName, '\0', sizeof(CellName)); + memset(ServiceName, '\0', sizeof(ServiceName)); + memset(realm_of_user, '\0', sizeof(realm_of_user)); + memset(realm_of_cell, '\0', sizeof(realm_of_cell)); + if (cell && cell[0]) + strcpy(Dmycell, cell); + else + memset(Dmycell, '\0', sizeof(Dmycell)); + + // NULL or empty cell returns information on local cell + if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell)) + { + // KFW_AFS_error(rc, "get_cellconfig()"); + return(rc); + } + + 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 skip_krb5_init; + } + + memset((char *)&increds, 0, sizeof(increds)); + + code = pkrb5_cc_get_principal(ctx, cc, &client_principal); + if (code) { + if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() ) + { + OutputDebugString("Principal Not Found for ccache\n"); + } + goto skip_krb5_init; + } + i = krb5_princ_realm(ctx, client_principal)->length; + if (i > REALM_SZ-1) + i = REALM_SZ-1; + strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i); + realm_of_user[i] = 0; + try_krb5 = 1; + + skip_krb5_init: +#ifdef USE_KRB4 + if ( !try_krb5 || !realm_of_user[0] ) { + if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS) + { + goto cleanup; + } + } +#else + goto cleanup; +#endif + strcpy(realm_of_cell, afs_realm_of_cell(&ak_cellconfig)); + + if (strlen(service) == 0) + strcpy(ServiceName, "afs"); + else + strcpy(ServiceName, service); + + if (strlen(cell) == 0) + strcpy(CellName, local_cell); + else + strcpy(CellName, cell); + + if (strlen(realm) == 0) + strcpy(RealmName, realm_of_cell); + else + strcpy(RealmName, realm); + + memset(&creds, '\0', sizeof(creds)); + + if ( try_krb5 ) { + int len; + + /* First try service/cell@REALM */ + if (code = pkrb5_build_principal(ctx, &increds.server, + strlen(RealmName), + RealmName, + ServiceName, + CellName, + 0)) + { + goto cleanup; + } + + increds.client = client_principal; + increds.times.endtime = 0; + /* Ask for DES since that is what V4 understands */ + increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; + + + if ( IsDebuggerPresent() ) { + pkrb5_unparse_name(ctx, increds.client, &cname); + pkrb5_unparse_name(ctx, increds.server, &sname); + OutputDebugString("Getting tickets for \""); + OutputDebugString(cname); + OutputDebugString("\" and service \""); + OutputDebugString(sname); + OutputDebugString("\"\n"); + cname = sname = 0; + } + + code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); + if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || + code == KRB5KRB_ERR_GENERIC /* heimdal */ || + code == KRB5KRB_AP_ERR_MSG_TYPE) { + /* Or service@REALM */ + pkrb5_free_principal(ctx,increds.server); + increds.server = 0; + code = pkrb5_build_principal(ctx, &increds.server, + strlen(RealmName), + RealmName, + ServiceName, + 0); + + if ( IsDebuggerPresent() ) { + char * cname, *sname; + pkrb5_unparse_name(ctx, increds.client, &cname); + pkrb5_unparse_name(ctx, increds.server, &sname); + OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n"); + OutputDebugString("Trying again: getting tickets for \""); + OutputDebugString(cname); + OutputDebugString("\" and service \""); + OutputDebugString(sname); + OutputDebugString("\"\n"); + pkrb5_free_unparsed_name(ctx,cname); + pkrb5_free_unparsed_name(ctx,sname); + cname = sname = 0; + } + + if (!code) + code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); + } + + if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || + code == KRB5KRB_ERR_GENERIC /* heimdal */ || + code == KRB5KRB_AP_ERR_MSG_TYPE) && + strcmp(RealmName, realm_of_cell)) { + /* Or service/cell@REALM_OF_CELL */ + strcpy(RealmName, realm_of_cell); + pkrb5_free_principal(ctx,increds.server); + increds.server = 0; + code = pkrb5_build_principal(ctx, &increds.server, + strlen(RealmName), + RealmName, + ServiceName, + CellName, + 0); + + if ( IsDebuggerPresent() ) { + char * cname, *sname; + pkrb5_unparse_name(ctx, increds.client, &cname); + pkrb5_unparse_name(ctx, increds.server, &sname); + OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n"); + OutputDebugString("Trying again: getting tickets for \""); + OutputDebugString(cname); + OutputDebugString("\" and service \""); + OutputDebugString(sname); + OutputDebugString("\"\n"); + pkrb5_free_unparsed_name(ctx,cname); + pkrb5_free_unparsed_name(ctx,sname); + cname = sname = 0; + } + + if (!code) + code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); + + + if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || + code == KRB5KRB_ERR_GENERIC /* heimdal */ || + code == KRB5KRB_AP_ERR_MSG_TYPE) { + /* Or service@REALM_OF_CELL */ + pkrb5_free_principal(ctx,increds.server); + increds.server = 0; + code = pkrb5_build_principal(ctx, &increds.server, + strlen(RealmName), + RealmName, + ServiceName, + 0); + + if ( IsDebuggerPresent() ) { + char * cname, *sname; + pkrb5_unparse_name(ctx, increds.client, &cname); + pkrb5_unparse_name(ctx, increds.server, &sname); + OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n"); + OutputDebugString("Trying again: getting tickets for \""); + OutputDebugString(cname); + OutputDebugString("\" and service \""); + OutputDebugString(sname); + OutputDebugString("\"\n"); + pkrb5_free_unparsed_name(ctx,cname); + pkrb5_free_unparsed_name(ctx,sname); + cname = sname = 0; + } + + if (!code) + code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); + } + } + + if (code) { + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"krb5_get_credentials returns: %d\n",code); + OutputDebugString(message); + } + try_krb5 = 0; + goto use_krb4; + } + + /* This code inserts the entire K5 ticket into the token + * No need to perform a krb524 translation which is + * commented out in the code below + */ + if (k5creds->ticket.length > MAXKTCTICKETLEN) + goto try_krb524d; + + memset(&aserver, '\0', sizeof(aserver)); + strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1); + strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1); + + memset(&atoken, '\0', sizeof(atoken)); + atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5; + atoken.startTime = k5creds->times.starttime; + atoken.endTime = k5creds->times.endtime; + memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length); + atoken.ticketLen = k5creds->ticket.length; + memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen); + + retry_gettoken5: + rc = pktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient); + if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) { + if ( rc == KTC_NOCM && retry < 20 ) { + Sleep(500); + retry++; + goto retry_gettoken5; + } + goto try_krb524d; + } + + if (atoken.kvno == btoken.kvno && + atoken.ticketLen == btoken.ticketLen && + !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) && + !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) + { + /* Success - Nothing to do */ + goto cleanup; + } + + // * Reset the "aclient" structure before we call ktc_SetToken. + // * This structure was first set by the ktc_GetToken call when + // * we were comparing whether identical tokens already existed. + + len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1); + strncpy(aclient.name, k5creds->client->data[0].data, len); + aclient.name[len] = '\0'; + + if ( k5creds->client->length > 1 ) { + char * p; + strcat(aclient.name, "."); + p = aclient.name + strlen(aclient.name); + len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - strlen(aclient.name) - 1); + strncpy(p, k5creds->client->data[1].data, len); + p[len] = '\0'; + } + aclient.instance[0] = '\0'; + + strcpy(aclient.cell, realm_of_cell); + + len = min(k5creds->client->realm.length,strlen(realm_of_cell)); + if ( strncmp(realm_of_cell, k5creds->client->realm.data, len) ) { + char * p; + strcat(aclient.name, "@"); + p = aclient.name + strlen(aclient.name); + len = min(k5creds->client->realm.length,MAXKTCNAMELEN - strlen(aclient.name) - 1); + strncpy(p, k5creds->client->realm.data, len); + p[len] = '\0'; + } + + if ( smbname ) { + strncpy(aclient.smbname, smbname, MAXRANDOMNAMELEN); + aclient.smbname[MAXRANDOMNAMELEN-1] = '\0'; + } else { + aclient.smbname[0] = '\0'; + } + + rc = pktc_SetToken(&aserver, &atoken, &aclient, 0); + if (!rc) + goto cleanup; /* We have successfully inserted the token */ + + try_krb524d: + /* Otherwise, the ticket could have been too large so try to + * convert using the krb524d running with the KDC + */ + code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds); + pkrb5_free_creds(ctx, k5creds); + if (code) { + if ( IsDebuggerPresent() ) { + char message[256]; + sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code); + OutputDebugString(message); + } + try_krb5 = 0; + goto use_krb4; + } + } else { + use_krb4: +#ifdef USE_KRB4 + code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds); + if (code == NO_TKT_FIL) { + // if the problem is that we have no krb4 tickets + // do not attempt to continue + goto cleanup; + } + if (code != KSUCCESS) + code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds); + + if (code != KSUCCESS) + { + if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS) + { + if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS) + { + goto cleanup; + } + } + else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS) + { + if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS) + { + goto cleanup; + } + } + else + { + goto cleanup; + } + } +#else + goto cleanup; +#endif + } + + memset(&aserver, '\0', sizeof(aserver)); + strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1); + strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1); + + memset(&atoken, '\0', sizeof(atoken)); + atoken.kvno = creds.kvno; + atoken.startTime = creds.issue_date; + atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime); + memcpy(&atoken.sessionKey, creds.session, 8); + atoken.ticketLen = creds.ticket_st.length; + memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen); + + retry_gettoken: + rc = pktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient); + if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) { + if ( rc == KTC_NOCM && retry < 20 ) { + Sleep(500); + retry++; + goto retry_gettoken; + } + KFW_AFS_error(rc, "ktc_GetToken()"); + code = rc; + goto cleanup; + } + + if (atoken.kvno == btoken.kvno && + atoken.ticketLen == btoken.ticketLen && + !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) && + !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) + { + goto cleanup; + } + + // * Reset the "aclient" structure before we call ktc_SetToken. + // * This structure was first set by the ktc_GetToken call when + // * we were comparing whether identical tokens already existed. + + strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1); + if (creds.pinst[0]) + { + strncat(aclient.name, ".", MAXKTCNAMELEN - 1); + strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1); + } + strcpy(aclient.instance, ""); + + if ( strcmp(realm_of_cell, creds.realm) ) + { + strncat(aclient.name, "@", MAXKTCNAMELEN - 1); + strncpy(aclient.name, creds.realm, MAXKTCREALMLEN - 1); + } + aclient.name[MAXKTCREALMLEN-1] = '\0'; + + strcpy(aclient.cell, CellName); + + if ( smbname ) { + strncpy(aclient.smbname, smbname, MAXRANDOMNAMELEN); + aclient.smbname[MAXRANDOMNAMELEN-1] = '\0'; + } else { + aclient.smbname[0] = '\0'; + } + + if (rc = pktc_SetToken(&aserver, &atoken, &aclient, 0)) + { + KFW_AFS_error(rc, "ktc_SetToken()"); + code = rc; + goto cleanup; + } + + cleanup: + if (cname) + pkrb5_free_unparsed_name(ctx,cname); + if (sname) + pkrb5_free_unparsed_name(ctx,sname); + if (client_principal) + pkrb5_free_principal(ctx,client_principal); + /* increds.client == client_principal */ + if (increds.server) + pkrb5_free_principal(ctx,increds.server); + if (cc && (cc != alt_cc)) + pkrb5_cc_close(ctx, cc); + if (ctx && (ctx != alt_ctx)) + pkrb5_free_context(ctx); + + return(rc? rc : code); +} + +/**************************************/ +/* afs_realm_of_cell(): */ +/**************************************/ +static char * +afs_realm_of_cell(struct afsconf_cell *cellconfig) +{ + static char krbrlm[REALM_SZ+1]=""; + krb5_context ctx = 0; + char ** realmlist=NULL; + krb5_error_code r; + + if (!cellconfig) + return 0; + + if (!pkrb5_init_context) + return 0; + + r = pkrb5_init_context(&ctx); + if ( !r ) + r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist); + if ( !r && realmlist && realmlist[0] ) { + strcpy(krbrlm, realmlist[0]); + pkrb5_free_host_realm(ctx, realmlist); + } + if (ctx) + pkrb5_free_context(ctx); + + if ( !krbrlm[0] ) + { + char *s = krbrlm; + char *t = cellconfig->name; + int c; + + while (c = *t++) + { + if (islower(c)) c=toupper(c); + *s++ = c; + } + *s++ = 0; + } + return(krbrlm); +} + +/**************************************/ +/* KFW_AFS_get_cellconfig(): */ +/**************************************/ +int +KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell) +{ + int rc; + char newcell[MAXCELLCHARS+1]; + + local_cell[0] = (char)0; + memset(cellconfig, 0, sizeof(*cellconfig)); + + /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */ + if (rc = pcm_GetRootCellName(local_cell)) + { + return(rc); + } + + if (strlen(cell) == 0) + strcpy(cell, local_cell); + + /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */ + strcpy(cellconfig->name, cell); + + return pcm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig); +} + +/**************************************/ +/* get_cellconfig_callback(): */ +/**************************************/ +static long +get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep) +{ + struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig; + + cc->hostAddr[cc->numServers] = *addrp; + strcpy(cc->hostName[cc->numServers], namep); + cc->numServers++; + return(0); +} + + +/**************************************/ +/* KFW_AFS_error(): */ +/**************************************/ +void +KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName) +{ + char message[256]; + const char *errText; + + // Using AFS defines as error messages for now, until Transarc + // gets back to me with "string" translations of each of these + // const. defines. + if (rc == KTC_ERROR) + errText = "KTC_ERROR"; + else if (rc == KTC_TOOBIG) + errText = "KTC_TOOBIG"; + else if (rc == KTC_INVAL) + errText = "KTC_INVAL"; + else if (rc == KTC_NOENT) + errText = "KTC_NOENT"; + else if (rc == KTC_PIOCTLFAIL) + errText = "KTC_PIOCTLFAIL"; + else if (rc == KTC_NOPIOCTL) + errText = "KTC_NOPIOCTL"; + else if (rc == KTC_NOCELL) + errText = "KTC_NOCELL"; + else if (rc == KTC_NOCM) + errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!"; + else + errText = "Unknown error!"; + + sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName); + + if ( IsDebuggerPresent() ) { + OutputDebugString(message); + OutputDebugString("\n"); + } + MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND); + return; +} + +static DWORD +GetServiceStatus( + LPSTR lpszMachineName, + LPSTR lpszServiceName, + DWORD *lpdwCurrentState) +{ + DWORD hr = NOERROR; + SC_HANDLE schSCManager = NULL; + SC_HANDLE schService = NULL; + DWORD fdwDesiredAccess = 0; + SERVICE_STATUS ssServiceStatus = {0}; + BOOL fRet = FALSE; + + *lpdwCurrentState = 0; + + fdwDesiredAccess = GENERIC_READ; + + schSCManager = OpenSCManager(lpszMachineName, + NULL, + fdwDesiredAccess); + + if(schSCManager == NULL) + { + hr = GetLastError(); + goto cleanup; + } + + schService = OpenService(schSCManager, + lpszServiceName, + fdwDesiredAccess); + + if(schService == NULL) + { + hr = GetLastError(); + goto cleanup; + } + + fRet = QueryServiceStatus(schService, + &ssServiceStatus); + + if(fRet == FALSE) + { + hr = GetLastError(); + goto cleanup; + } + + *lpdwCurrentState = ssServiceStatus.dwCurrentState; + +cleanup: + + CloseServiceHandle(schService); + CloseServiceHandle(schSCManager); + + return(hr); +} + +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, // [out, optional] - DLL handle + int* pindex, // [out, optional] - index of last func loaded (-1 if none) + int cleanup, // cleanup function pointers and unload on error + int go_on, // continue loading even if some functions cannot be loaded + int silent // do not pop-up a system dialog if DLL cannot be loaded + ) +{ + 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; +} + +BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig) +{ + krb5_context ctx = 0; + krb5_ccache cc = 0; + krb5_error_code code; + krb5_data pwdata; + const char * realm = 0; + krb5_principal principal = 0; + char * pname = 0; + char password[PROBE_PASSWORD_LEN+1]; + BOOL serverReachable = 0; + + realm = afs_realm_of_cell(cellconfig); // do not free + + code = pkrb5_build_principal(ctx, &principal, strlen(realm), + realm, PROBE_USERNAME, NULL, NULL); + if ( code ) goto cleanup; + + code = KFW_get_ccache(ctx, principal, &cc); + if ( code ) goto cleanup; + + code = pkrb5_unparse_name(ctx, principal, &pname); + if ( code ) goto cleanup; + + pwdata.data = password; + pwdata.length = PROBE_PASSWORD_LEN; + code = pkrb5_c_random_make_octets(ctx, &pwdata); + if (code) { + int i; + for ( i=0 ; i +#include +#include +#include + +#define MAXCELLCHARS 64 +#define MAXHOSTCHARS 64 +#define MAXHOSTSPERCELL 8 +#define TRANSARCAFSDAEMON "TransarcAFSDaemon" + +void KFW_initialize(void); +void KFW_cleanup(void); +int KFW_is_available(void); +int KFW_AFS_destroy_tickets_for_cell(char *); +int KFW_AFS_renew_expiring_tokens(void); +int KFW_AFS_get_cred( char * username, + char * instance, + char * cell, + char * password, + int lifetime, + char * smbname, + char ** reasonP ); +int KFW_AFS_renew_token_for_cell(char * cell); +int KFW_AFS_renew_tokens_for_all_cells(void); +BOOL KFW_AFS_wait_for_service_start(void); +BOOL KFW_probe_kdc(struct afsconf_cell *); +int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *); +void KFW_import_windows_lsa(void); + +/* From afs/krb_prot.h */ +/* values for kerb error codes */ +#define KERB_ERR_OK 0 +#define KERB_ERR_NAME_EXP 1 +#define KERB_ERR_SERVICE_EXP 2 +#define KERB_ERR_AUTH_EXP 3 +#define KERB_ERR_PKT_VER 4 +#define KERB_ERR_NAME_MAST_KEY_VER 5 +#define KERB_ERR_SERV_MAST_KEY_VER 6 +#define KERB_ERR_BYTE_ORDER 7 +#define KERB_ERR_PRINCIPAL_UNKNOWN 8 +#define KERB_ERR_PRINCIPAL_NOT_UNIQUE 9 +#define KERB_ERR_NULL_KEY 10 + +/* From afs/krb.h */ +#define RD_AP_TIME 37 /* delta_t too big */ +#define INTK_BADPW 62 /* Incorrect password */ + +#define PROBE_USERNAME "OPENAFS-KDC-PROBE" +#define PROBE_PASSWORD_LEN 16 + +#ifdef __cplusplus +} +#endif +#endif /* AFSKFW_H */ diff --git a/src/WINNT/afsd/afslogon.c b/src/WINNT/afsd/afslogon.c index 9e6bac974..6fd8924f3 100644 --- a/src/WINNT/afsd/afslogon.c +++ b/src/WINNT/afsd/afslogon.c @@ -427,8 +427,11 @@ DWORD APIENTRY NPLogonNotify( /* if Integrated Logon only */ if (ISLOGONINTEGRATED(LogonOption) && !ISHIGHSECURITY(LogonOption)) { - code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON, - uname, "", cell, password,uname, 0, &pw_exp, 0, + if ( KFW_is_available() ) + code = KFW_AFS_get_cred(uname, "", cell, password, 0, uname, &reason); + else + code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON, + uname, "", cell, password, uname, 0, &pw_exp, 0, &reason); DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2","Code[%x]", code); @@ -443,7 +446,10 @@ DWORD APIENTRY NPLogonNotify( /* if Integrated Logon and High Security pass random generated name*/ else if (ISLOGONINTEGRATED(LogonOption) && ISHIGHSECURITY(LogonOption)) { - code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON, + if ( KFW_is_available() ) + code = KFW_AFS_get_cred(uname, "", cell, password, 0, RandomName, &reason); + else + code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON, uname, "", cell, password,RandomName, 0, &pw_exp, 0, &reason); DebugEvent("AFS AfsLogon - (Both)ka_UserAuthenticateGeneral2","Code[%x] RandomName[%s]", @@ -499,6 +505,10 @@ DWORD APIENTRY NPLogonNotify( retryInterval -= sleepInterval; } + /* remove any kerberos 5 tickets currently held by the SYSTEM account */ + if ( KFW_is_available() ) + KFW_AFS_destroy_tickets_for_cell(cell); + if (code) { char msg[128]; sprintf(msg, "Integrated login failed: %s", reason); diff --git a/src/WINNT/client_creds/NTMakefile b/src/WINNT/client_creds/NTMakefile index 461d5dcb5..9d72cfc97 100644 --- a/src/WINNT/client_creds/NTMakefile +++ b/src/WINNT/client_creds/NTMakefile @@ -7,7 +7,7 @@ # include the AFSD source tree on our inclusion path -AFSDEV_AUXCDEFINES = $(AFSDEV_AUXCDEFINES) /D"_AFXDLL" -I..\afsd -I..\client_config -I..\kfw\inc\loadfuncs -I..\kfw\inc\krb5 -I..\kfw\inc\leash +AFSDEV_AUXCDEFINES = $(AFSDEV_AUXCDEFINES) /D"_AFXDLL" -I..\afsd -I..\client_config -I..\kfw\inc\krb5 # include the primary makefile RELDIR=WINNT\client_creds @@ -35,7 +35,7 @@ EXEOBJS = \ $(OUT)\window.obj EXECOBJS = \ - $(OUT)\afskfw.obj + $(OUT)\ipaddrchg.obj EXERES = \ $(OUT)\afscreds_stub.res @@ -67,7 +67,10 @@ EXELIBS = \ $(DESTDIR)\lib\afs\TaLocale.lib \ $(DESTDIR)\lib\lanahelper.lib \ $(DESTDIR)\lib\afsrxkad.lib \ - $(DESTDIR)\lib\afsdes.lib + $(DESTDIR)\lib\afsdes.lib \ + $(DESTDIR)\lib\afsauthent.lib \ + $(DESTDIR)\lib\libafsconf.lib \ + $(DESTDIR)\lib\afskfw.lib ############################################################################ # diff --git a/src/WINNT/client_creds/afscreds.h b/src/WINNT/client_creds/afscreds.h index a5aad5b3c..524457e40 100644 --- a/src/WINNT/client_creds/afscreds.h +++ b/src/WINNT/client_creds/afscreds.h @@ -30,6 +30,7 @@ extern "C" { #include #include #include +#include #ifdef __cplusplus } #endif @@ -92,6 +93,7 @@ typedef struct TCHAR szHelpFile[ MAX_PATH ]; osi_mutex_t expirationCheckLock; osi_mutex_t credsLock; + TCHAR SmbName[ MAXRANDOMNAMELEN ]; } GLOBALS; extern GLOBALS g; diff --git a/src/WINNT/client_creds/afskfw-int.h b/src/WINNT/client_creds/afskfw-int.h deleted file mode 100644 index 139bceb93..000000000 --- a/src/WINNT/client_creds/afskfw-int.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2003 SkyRope, LLC - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - Neither the name of Skyrope, LLC nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission from Skyrope, LLC. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Portions of this code are derived from portions of the MIT - * Leash Ticket Manager and LoadFuncs utilities. For these portions the - * following copyright applies. - * - * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology. - * All rights reserved. - * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, 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 M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - * - */ - -#ifndef AFSKRB5_INT_H -#define AFSKRB5_INT_H - -#include -#ifdef USE_MS2MIT -#define SECURITY_WIN32 -#include -#include -#endif /* USE_MS2MIT */ -#include -#include -#include -#include - -#ifdef USE_MS2MIT -#include -#endif /* USE_MS2MIT */ - -#include -#include - -#include - -/* Defined in the KRBV4W32 version of krb.h but not the Kerberos V version */ -/* Required for some of the loadfuncs headers */ -typedef struct ktext far *KTEXT; -typedef struct ktext far *KTEXT_FP; -#include - -/* AFS has its own version of com_err.h */ -typedef afs_int32 errcode_t; - -#include -#include -#include -#include -#include -#include -#include - -// service definitions -#define SERVICE_DLL "advapi32.dll" -typedef SC_HANDLE (WINAPI *FP_OpenSCManagerA)(char *, char *, DWORD); -typedef SC_HANDLE (WINAPI *FP_OpenServiceA)(SC_HANDLE, char *, DWORD); -typedef BOOL (WINAPI *FP_QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS); -typedef BOOL (WINAPI *FP_CloseServiceHandle)(SC_HANDLE); - -#define KRB5_DEFAULT_LIFE 60*60*10 /* 10 hours */ -#define LSA_CCNAME "MSLSA:" - -#define PROBE_USERNAME "OPENAFS-KDC-PROBE" -#define PROBE_PASSWORD_LEN 16 - -#define MAXCELLCHARS 64 -#define MAXHOSTCHARS 64 -#define MAXHOSTSPERCELL 8 -#define TRANSARCAFSDAEMON "TransarcAFSDaemon" -typedef struct { - char name[MAXCELLCHARS]; - short numServers; - short flags; - struct sockaddr_in hostAddr[MAXHOSTSPERCELL]; - char hostName[MAXHOSTSPERCELL][MAXHOSTCHARS]; - char *linkedCell; -} afsconf_cell; - -struct ktc_token { - time_t startTime; - time_t endTime; - struct ktc_encryptionKey sessionKey; - short kvno; /* XXX UNALIGNED */ - int ticketLen; - char ticket[MAXKTCTICKETLEN]; -}; - -#define KTC_ERROR 11862784L -#define KTC_TOOBIG 11862785L -#define KTC_INVAL 11862786L -#define KTC_NOENT 11862787L -#define KTC_PIOCTLFAIL 11862788L -#define KTC_NOPIOCTL 11862789L -#define KTC_NOCELL 11862790L -#define KTC_NOCM 11862791L - -/* User Query data structures and functions */ - -struct textField { - char * buf; /* Destination buffer address */ - int len; /* Destination buffer length */ - char * label; /* Label for this field */ - char * def; /* Default response for this field */ - int echo; /* 0 = no, 1 = yes, 2 = asterisks */ -}; - -#define ID_TEXT 150 -#define ID_MID_TEXT 300 - -struct principal_ccache_data { - struct principal_ccache_data * next; - char * principal; - char * ccache_name; - int from_lsa; - int expired; - int expiration_time; - int renew; -}; - -struct cell_principal_map { - struct cell_principal_map * next; - char * cell; - char * principal; - int active; -}; - -/* In order to avoid including the private CCAPI headers */ -typedef int cc_int32; - -#define CC_API_VER_1 1 -#define CC_API_VER_2 2 - -#define CCACHE_API cc_int32 - -/* -** The Official Error Codes -*/ -#define CC_NOERROR 0 -#define CC_BADNAME 1 -#define CC_NOTFOUND 2 -#define CC_END 3 -#define CC_IO 4 -#define CC_WRITE 5 -#define CC_NOMEM 6 -#define CC_FORMAT 7 -#define CC_LOCKED 8 -#define CC_BAD_API_VERSION 9 -#define CC_NO_EXIST 10 -#define CC_NOT_SUPP 11 -#define CC_BAD_PARM 12 -#define CC_ERR_CACHE_ATTACH 13 -#define CC_ERR_CACHE_RELEASE 14 -#define CC_ERR_CACHE_FULL 15 -#define CC_ERR_CRED_VERSION 16 - -enum { - CC_CRED_VUNKNOWN = 0, // For validation - CC_CRED_V4 = 1, - CC_CRED_V5 = 2, - CC_CRED_VMAX = 3 // For validation -}; - -typedef struct opaque_dll_control_block_type* apiCB; -typedef struct _infoNC { - char* name; - char* principal; - cc_int32 vers; -} infoNC; - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_initialize, - ( - apiCB** cc_ctx, // < DLL's primary control structure. - // returned here, passed everywhere else - cc_int32 api_version, // > ver supported by caller (use CC_API_VER_1) - cc_int32* api_supported, // < if ~NULL, max ver supported by DLL - const char** vendor // < if ~NULL, vendor name in read only C string - ) -); - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_shutdown, - ( - apiCB** cc_ctx // <> DLL's primary control structure. NULL after - ) -); - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_get_NC_info, - ( - apiCB* cc_ctx, // > DLL's primary control structure - struct _infoNC*** ppNCi // < (NULL before call) null terminated, - // list of a structs (free via cc_free_infoNC()) - ) -); - -TYPEDEF_FUNC( -CCACHE_API, -CALLCONV_C, -cc_free_NC_info, - ( - apiCB* cc_ctx, - struct _infoNC*** ppNCi // < free list of structs returned by - // cc_get_cache_names(). set to NULL on return - ) -); -#define CCAPI_DLL "krbcc32.dll" - -/* Function Prototypes */ -DWORD GetServiceStatus(LPSTR, LPSTR, DWORD *); -void KFW_AFS_error(LONG, LPCSTR); - -void UnloadFuncs(FUNC_INFO [], HINSTANCE); -int LoadFuncs(const char*, FUNC_INFO [], HINSTANCE*, int*, int, int, int); -int KFW_get_ccache(krb5_context, krb5_principal, krb5_ccache *); -int KFW_error(krb5_error_code, LPCSTR, int, krb5_context *, krb5_ccache *); -int KFW_kinit(krb5_context, krb5_ccache, HWND, char *, char *, krb5_deltat, - DWORD, DWORD, krb5_deltat, DWORD, DWORD); -int KFW_AFS_get_cred(char *, char *, char *, char *, int, char **); -int KFW_renew(krb5_context, krb5_ccache); -int KFW_destroy(krb5_context, krb5_ccache); -BOOL KFW_ms2mit(krb5_context, krb5_ccache, BOOL); -int KFW_AFS_unlog(void); -int KFW_AFS_klog(krb5_context, krb5_ccache, char*, char*, char*, int); -void KFW_import_ccache_data(void); -void KFW_import_windows_lsa(void); -BOOL MSLSA_IsKerberosLogon(); - -/* From afs/krb_prot.h */ -/* values for kerb error codes */ -#define KERB_ERR_OK 0 -#define KERB_ERR_NAME_EXP 1 -#define KERB_ERR_SERVICE_EXP 2 -#define KERB_ERR_AUTH_EXP 3 -#define KERB_ERR_PKT_VER 4 -#define KERB_ERR_NAME_MAST_KEY_VER 5 -#define KERB_ERR_SERV_MAST_KEY_VER 6 -#define KERB_ERR_BYTE_ORDER 7 -#define KERB_ERR_PRINCIPAL_UNKNOWN 8 -#define KERB_ERR_PRINCIPAL_NOT_UNIQUE 9 -#define KERB_ERR_NULL_KEY 10 -#endif /* AFSKFW_INT_H */ diff --git a/src/WINNT/client_creds/afskfw.c b/src/WINNT/client_creds/afskfw.c deleted file mode 100644 index d64df2142..000000000 --- a/src/WINNT/client_creds/afskfw.c +++ /dev/null @@ -1,3597 +0,0 @@ -/* - * Copyright (c) 2003 SkyRope, LLC - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - Neither the name of Skyrope, LLC nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission from Skyrope, LLC. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Portions of this code are derived from portions of the MIT - * Leash Ticket Manager and LoadFuncs utilities. For these portions the - * following copyright applies. - * - * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology. - * All rights reserved. - * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, 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 M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. Furthermore if you modify this software you must label - * your software as modified software and not distribute it in such a - * fashion that it might be confused with the original M.I.T. software. - * M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - * - */ - - -#define USE_MS2MIT -#define USE_KRB4 -#include "afskfw-int.h" -#include "afskfw.h" -#include "creds.h" - -#include -#include /* for life_to_time */ - -/* - * TIMING _____________________________________________________________________ - * - */ - -#define cminREMIND_TEST 1 // test every minute for expired creds -#define cminREMIND_WARN 15 // warn if creds expire in 15 minutes -#define cminRENEW 20 // renew creds when there are 20 minutes remaining -#define cminMINLIFE 30 // minimum life of Kerberos creds - -#define c100ns1SECOND (LONGLONG)10000000 -#define cmsec1SECOND 1000 -#define cmsec1MINUTE 60000 -#define csec1MINUTE 60 - -/* Function Pointer Declarations for Delayed Loading */ -// CCAPI -DECL_FUNC_PTR(cc_initialize); -DECL_FUNC_PTR(cc_shutdown); -DECL_FUNC_PTR(cc_get_NC_info); -DECL_FUNC_PTR(cc_free_NC_info); - -// leash functions -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); - -// krb5 functions -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_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); - -// Krb524 functions -DECL_FUNC_PTR(krb524_init_ets); -DECL_FUNC_PTR(krb524_convert_creds_kdc); - -// krb4 functions -DECL_FUNC_PTR(krb_get_cred); -DECL_FUNC_PTR(tkt_string); -DECL_FUNC_PTR(krb_get_tf_realm); -DECL_FUNC_PTR(krb_mk_req); - -// ComErr functions -DECL_FUNC_PTR(com_err); -DECL_FUNC_PTR(error_message); - -// Profile functions -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); - -// Service functions -DECL_FUNC_PTR(OpenSCManagerA); -DECL_FUNC_PTR(OpenServiceA); -DECL_FUNC_PTR(QueryServiceStatus); -DECL_FUNC_PTR(CloseServiceHandle); -#ifdef USE_MS2MIT -DECL_FUNC_PTR(LsaNtStatusToWinError); -#endif /* USE_MS2MIT */ - -#ifdef USE_MS2MIT -// LSA Functions -DECL_FUNC_PTR(LsaConnectUntrusted); -DECL_FUNC_PTR(LsaLookupAuthenticationPackage); -DECL_FUNC_PTR(LsaCallAuthenticationPackage); -DECL_FUNC_PTR(LsaFreeReturnBuffer); -DECL_FUNC_PTR(LsaGetLogonSessionData); -#endif /* USE_MS2MIT */ - -// AFS36 Token Functions -DECL_FUNC_PTR(ktc_ListTokens); -DECL_FUNC_PTR(ktc_GetToken); -DECL_FUNC_PTR(ktc_SetToken); -DECL_FUNC_PTR(ktc_ForgetAllTokens); - -// AFS36 Config Functions -DECL_FUNC_PTR(cm_SearchCellFile); -DECL_FUNC_PTR(cm_GetRootCellName); - -// CCAPI -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 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_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 k4_fi[] = { - MAKE_FUNC_INFO(krb_get_cred), - MAKE_FUNC_INFO(krb_get_tf_realm), - MAKE_FUNC_INFO(krb_mk_req), - MAKE_FUNC_INFO(tkt_string), - END_FUNC_INFO -}; - -FUNC_INFO k524_fi[] = { - MAKE_FUNC_INFO(krb524_init_ets), - MAKE_FUNC_INFO(krb524_convert_creds_kdc), - 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), -#ifdef USE_MS2MIT - MAKE_FUNC_INFO(LsaNtStatusToWinError), -#endif /* USE_MS2MIT */ - END_FUNC_INFO -}; - -#ifdef USE_MS2MIT -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 -}; -#endif /* USE_MS2MIT */ - -FUNC_INFO afst_fi[] = { - MAKE_FUNC_INFO(ktc_ListTokens), - MAKE_FUNC_INFO(ktc_GetToken), - MAKE_FUNC_INFO(ktc_SetToken), - MAKE_FUNC_INFO(ktc_ForgetAllTokens), - END_FUNC_INFO -}; - -FUNC_INFO afsc_fi[] = { - MAKE_FUNC_INFO(cm_SearchCellFile), - MAKE_FUNC_INFO(cm_GetRootCellName), - END_FUNC_INFO -}; - -/* Static Prototypes */ -static char *afs_realm_of_cell(afsconf_cell *); -static long get_cellconfig_callback(void *, struct sockaddr_in *, char *); -static int get_cellconfig(char *, afsconf_cell *, char *); -static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context, - void *data, const char *name, const char *banner, int num_prompts, - krb5_prompt prompts[]); - - -/* Static Declarations */ -static int inited = 0; -static int mid_cnt = 0; -static struct textField * mid_tb = NULL; -static HINSTANCE hKrb5 = 0; -static HINSTANCE hKrb4 = 0; -static HINSTANCE hKrb524 = 0; -#ifdef USE_MS2MIT -static HINSTANCE hSecur32 = 0; -#endif /* USE_MS2MIT */ -static HINSTANCE hAdvApi32 = 0; -static HINSTANCE hAfsTokens = 0; -static HINSTANCE hAfsConf = 0; -static HINSTANCE hComErr = 0; -static HINSTANCE hService = 0; -static HINSTANCE hProfile = 0; -static HINSTANCE hLeash = 0; -static HINSTANCE hCCAPI = 0; -static struct principal_ccache_data * princ_cc_data = NULL; -static struct cell_principal_map * cell_princ_map = NULL; - -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(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0); - LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0); - LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0); -#ifdef USE_MS2MIT - LoadFuncs(SECUR32_DLL, lsa_fi, &hSecur32, 0, 1, 1, 1); -#endif /* USE_MS2MIT */ - LoadFuncs(KRB524_DLL, k524_fi, &hKrb524, 0, 1, 1, 1); - LoadFuncs(PROFILE_DLL, profile_fi, &hProfile, 0, 1, 0, 0); - LoadFuncs(AFSTOKENS_DLL, afst_fi, &hAfsTokens, 0, 1, 0, 0); - LoadFuncs(AFSCONF_DLL, afsc_fi, &hAfsConf, 0, 1, 0, 0); - LoadFuncs(LEASH_DLL, leash_fi, &hLeash, 0, 1, 0, 0); - LoadFuncs(CCAPI_DLL, ccapi_fi, &hCCAPI, 0, 1, 0, 0); - - if ( KFW_is_available() ) { - char rootcell[MAXCELLCHARS+1]; -#ifdef USE_MS2MIT - KFW_import_windows_lsa(); -#endif /* USE_MS2MIT */ - KFW_import_ccache_data(); - KFW_AFS_renew_expiring_tokens(); - - /* WIN32 NOTE: no way to get max chars */ - if (!pcm_GetRootCellName(rootcell)) - KFW_AFS_renew_token_for_cell(rootcell); - } - } - ReleaseMutex(hMutex); - CloseHandle(hMutex); - } -} - -void -KFW_cleanup(void) -{ - if (hKrb5) - FreeLibrary(hKrb5); - if (hKrb4) - FreeLibrary(hKrb4); - if (hProfile) - FreeLibrary(hProfile); - if (hAfsTokens) - FreeLibrary(hAfsTokens); - if (hAfsConf) - FreeLibrary(hAfsConf); - if (hComErr) - FreeLibrary(hComErr); - if (hService) - FreeLibrary(hService); -#ifdef USE_MS2MIT - if (hSecur32) - FreeLibrary(hSecur32); -#endif /* USE_MS2MIT */ - if (hKrb524) - FreeLibrary(hKrb524); - if (hLeash) - FreeLibrary(hLeash); - if (hCCAPI) - FreeLibrary(hCCAPI); -} - -static char OpenAFSConfigKeyName[] = "SOFTWARE\\OpenAFS\\Client"; - -int -KFW_is_available(void) -{ - HKEY parmKey; - DWORD code, len; - DWORD enableKFW = 1; - - code = RegOpenKeyEx(HKEY_CURRENT_USER, OpenAFSConfigKeyName, - 0, KEY_QUERY_VALUE, &parmKey); - if (code != ERROR_SUCCESS) - code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, OpenAFSConfigKeyName, - 0, KEY_QUERY_VALUE, &parmKey); - if (code == ERROR_SUCCESS) { - len = sizeof(enableKFW); - code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL, - (BYTE *) &enableKFW, &len); - if (code != ERROR_SUCCESS) { - enableKFW = 1; - } - RegCloseKey (parmKey); - } - - if ( !enableKFW ) - return FALSE; - - KFW_initialize(); - if ( hKrb5 && hComErr && hService && -#ifdef USE_MS2MIT - hSecur32 && -#endif /* USE_MS2MIT */ - hKrb524 && - hProfile && hAfsTokens && hAfsConf && hLeash && hCCAPI ) - return TRUE; - return FALSE; -} - -int -KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName, - int FreeContextFlag, krb5_context * ctx, - krb5_ccache * cache) -{ - char message[256]; - const char *errText; - int krb5Error = ((int)(rc & 255)); - - /* - switch (krb5Error) - { - // Wrong password - case 31: - case 8: - return; - } - */ - - errText = perror_message(rc); - _snprintf(message, sizeof(message), - "%s\n(Kerberos error %ld)\n\n%s failed", - errText, - krb5Error, - FailedFunctionName); - - if ( IsDebuggerPresent() ) - OutputDebugString(message); - - MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR | - MB_TASKMODAL | - MB_SETFOREGROUND); - if (FreeContextFlag == 1) - { - if (ctx && *ctx != NULL) - { - if (cache && *cache != NULL) { - pkrb5_cc_close(*ctx, *cache); - *cache = NULL; - } - - pkrb5_free_context(*ctx); - *ctx = NULL; - } - } - - return rc; -} - -void -KFW_AFS_update_princ_ccache_data(krb5_context ctx, krb5_ccache cc, int lsa) -{ - struct principal_ccache_data * next = princ_cc_data; - krb5_principal principal = 0; - char * pname = NULL; - const char * ccname = NULL; - krb5_error_code code = 0; - krb5_error_code cc_code = 0; - krb5_cc_cursor cur; - krb5_creds creds; - krb5_flags flags=0; - krb5_timestamp now; - - if (ctx == 0 || cc == 0) - return; - - code = pkrb5_cc_get_principal(ctx, cc, &principal); - if ( code ) return; - - code = pkrb5_unparse_name(ctx, principal, &pname); - if ( code ) goto cleanup; - - ccname = pkrb5_cc_get_name(ctx, cc); - if (!ccname) goto cleanup; - - // Search the existing list to see if we have a match - if ( next ) { - for ( ; next ; next = next->next ) { - if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccname) ) - break; - } - } - - // If not, match add a new node to the beginning of the list and assign init it - if ( !next ) { - next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data)); - next->next = princ_cc_data; - princ_cc_data = next; - next->principal = _strdup(pname); - next->ccache_name = _strdup(ccname); - next->from_lsa = lsa; - next->expired = 1; - next->expiration_time = 0; - next->renew = 0; - } - - flags = 0; // turn off OPENCLOSE mode - code = pkrb5_cc_set_flags(ctx, cc, flags); - if ( code ) goto cleanup; - - code = pkrb5_timeofday(ctx, &now); - - cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur); - - while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) { - if ( creds.ticket_flags & TKT_FLG_INITIAL ) { - int valid; - // we found the ticket we are looking for - // check validity of timestamp - // We add a 5 minutes fudge factor to compensate for potential - // clock skew errors between the KDC and client OS - - valid = ((creds.times.starttime > 0) && - now >= (creds.times.starttime - 300) && - now < (creds.times.endtime + 300) && - !(creds.ticket_flags & TKT_FLG_INVALID)); - - if ( next->from_lsa) { - next->expired = 0; - next->expiration_time = creds.times.endtime; - next->renew = 1; - } else if ( valid ) { - next->expired = 0; - next->expiration_time = creds.times.endtime; - next->renew = (creds.times.renew_till > creds.times.endtime) && - (creds.ticket_flags & TKT_FLG_RENEWABLE); - } else { - next->expired = 1; - next->expiration_time = 0; - next->renew = 0; - } - - pkrb5_free_cred_contents(ctx, &creds); - cc_code = KRB5_CC_END; - break; - } - pkrb5_free_cred_contents(ctx, &creds); - } - - if (cc_code == KRB5_CC_END) { - code = pkrb5_cc_end_seq_get(ctx, cc, &cur); - if (code) goto cleanup; - } - - cleanup: - flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE - code = pkrb5_cc_set_flags(ctx, cc, flags); - - if ( pname ) - pkrb5_free_unparsed_name(ctx,pname); - if ( principal ) - pkrb5_free_principal(ctx,principal); -} - -int -KFW_AFS_find_ccache_for_principal(krb5_context ctx, char * principal, char **ccache, int valid_only) -{ - struct principal_ccache_data * next = princ_cc_data; - char * response = NULL; - - if ( !principal || !ccache ) - return 0; - - while ( next ) { - if ( (!valid_only || !next->expired) && !strcmp(next->principal,principal) ) { - if (response) { - // we always want to prefer the MS Kerberos LSA cache or - // the cache afscreds created specifically for the principal - // if the current entry is either one, drop the previous find - if ( next->from_lsa || !strcmp(next->ccache_name,principal) ) - free(response); - } - response = _strdup(next->ccache_name); - // MS Kerberos LSA is our best option so use it and quit - if ( next->from_lsa ) - break; - } - next = next->next; - } - - if ( response ) { - *ccache = response; - return 1; - } - return 0; -} - -void -KFW_AFS_delete_princ_ccache_data(krb5_context ctx, char * pname, char * ccname) -{ - struct principal_ccache_data ** next = &princ_cc_data; - - if ( !pname && !ccname ) - return; - - while ( (*next) ) { - if ( !strcmp((*next)->principal,pname) || - !strcmp((*next)->ccache_name,ccname) ) { - void * temp; - free((*next)->principal); - free((*next)->ccache_name); - temp = (*next); - (*next) = (*next)->next; - free(temp); - } - } -} - -void -KFW_AFS_update_cell_princ_map(krb5_context ctx, char * cell, char *pname, int active) -{ - struct cell_principal_map * next = cell_princ_map; - - // Search the existing list to see if we have a match - if ( next ) { - for ( ; next ; next = next->next ) { - if ( !strcmp(next->cell, cell) ) { - if ( !strcmp(next->principal,pname) ) { - next->active = active; - break; - } else { - // OpenAFS currently has a restriction of one active token per cell - // Therefore, whenever we update the table with a new active cell we - // must mark all of the other principal to cell entries as inactive. - if (active) - next->active = 0; - } - } - } - } - - // If not, match add a new node to the beginning of the list and assign init it - if ( !next ) { - next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map)); - next->next = cell_princ_map; - cell_princ_map = next; - next->principal = _strdup(pname); - next->cell = _strdup(cell); - next->active = active; - } -} - -void -KFW_AFS_delete_cell_princ_maps(krb5_context ctx, char * pname, char * cell) -{ - struct cell_principal_map ** next = &cell_princ_map; - - if ( !pname && !cell ) - return; - - while ( (*next) ) { - if ( !strcmp((*next)->principal,pname) || - !strcmp((*next)->cell,cell) ) { - void * temp; - free((*next)->principal); - free((*next)->cell); - temp = (*next); - (*next) = (*next)->next; - free(temp); - } - } -} - -// Returns (if possible) a principal which has been known in -// the past to have been used to obtain tokens for the specified -// cell. -// TODO: Attempt to return one which has not yet expired by checking -// the principal/ccache data -int -KFW_AFS_find_principals_for_cell(krb5_context ctx, char * cell, char **principals[], int active_only) -{ - struct cell_principal_map * next_map = cell_princ_map; - const char * princ = NULL; - int count = 0, i; - - if ( !cell ) - return 0; - - while ( next_map ) { - if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) { - count++; - } - next_map = next_map->next; - } - - if ( !principals || !count ) - return count; - - *principals = (char **) malloc(sizeof(char *) * count); - for ( next_map = cell_princ_map, i=0 ; next_map && inext ) - { - if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) { - (*principals)[i++] = _strdup(next_map->principal); - } - } - return count; -} - -int -KFW_AFS_find_cells_for_princ(krb5_context ctx, char * pname, char **cells[], int active_only) -{ - int count = 0, i; - struct cell_principal_map * next_map = cell_princ_map; - const char * princ = NULL; - - if ( !pname ) - return 0; - - while ( next_map ) { - if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) { - count++; - } - next_map = next_map->next; - } - - if ( !cells ) - return count; - - *cells = (char **) malloc(sizeof(char *) * count); - for ( next_map = cell_princ_map, i=0 ; next_map && inext ) - { - if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) { - (*cells)[i++] = _strdup(next_map->cell); - } - } - return count; -} - -/* Given a principal return an existing ccache or create one and return */ -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; - - if ( !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,TRUE) && - !KFW_AFS_find_ccache_for_principal(ctx,pname,&ccname,FALSE)) { - ccname = (char *)malloc(strlen(pname) + 5); - sprintf(ccname,"API:%s",pname); - } - 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); -} - -#ifdef USE_MS2MIT -// Import Microsoft Credentials into a new MIT ccache -void -KFW_import_windows_lsa(void) -{ - krb5_context ctx = 0; - krb5_ccache cc = 0; - krb5_principal princ = 0; - char * pname = NULL; - krb5_data * realm; - krb5_error_code code; - char cell[128]=""; - int i; - - if (!pkrb5_init_context) - return; - -#ifdef COMMENT - if ( !MSLSA_IsKerberosLogon() ) - return; -#endif - - code = pkrb5_init_context(&ctx); - if (code) goto cleanup; - - code = pkrb5_cc_resolve(ctx, LSA_CCNAME, &cc); - if (code) goto cleanup; - - KFW_AFS_update_princ_ccache_data(ctx, cc, TRUE); - - code = pkrb5_cc_get_principal(ctx, cc, &princ); - if ( code ) goto cleanup; - - code = pkrb5_unparse_name(ctx,princ,&pname); - if ( code ) goto cleanup; - - realm = krb5_princ_realm(ctx, princ); - for ( i=0; ilength; i++ ) { - cell[i] = tolower(realm->data[i]); - } - cell[i] = '\0'; - - code = KFW_AFS_klog(ctx, cc, "afs", cell, realm->data, pLeash_get_default_lifetime()); - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"KFW_AFS_klog() returns: %d\n",code); - OutputDebugString(message); - } - if ( code ) goto cleanup; - - KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE); - - cleanup: - if (pname) - pkrb5_free_unparsed_name(ctx,pname); - if (princ) - pkrb5_free_principal(ctx,princ); - if (cc) - pkrb5_cc_close(ctx,cc); - if (ctx) - pkrb5_free_context(ctx); -} -#endif /* USE_MS2MIT */ - -// If there are existing MIT credentials, copy them to a new -// ccache named after the principal - -// Enumerate all existing MIT ccaches and construct entries -// in the principal_ccache table - -// Enumerate all existing AFS Tokens and construct entries -// in the cell_principal table -void -KFW_import_ccache_data(void) -{ - krb5_context ctx = 0; - krb5_ccache cc = 0; - krb5_principal principal = 0; - krb5_creds creds; - krb5_error_code code; - krb5_error_code cc_code; - krb5_cc_cursor cur; - apiCB * cc_ctx = 0; - struct _infoNC ** pNCi = NULL; - int i, j, flags; - - if ( !pcc_initialize ) - return; - - if ( IsDebuggerPresent() ) - OutputDebugString("KFW_import_ccache_data()\n"); - - code = pcc_initialize(&cc_ctx, CC_API_VER_2, NULL, NULL); - if (code) goto cleanup; - - code = pcc_get_NC_info(cc_ctx, &pNCi); - if (code) goto cleanup; - - code = pkrb5_init_context(&ctx); - if (code) goto cleanup; - - for ( i=0; pNCi[i]; i++ ) { - if ( pNCi[i]->vers != CC_CRED_V5 ) - continue; - if ( IsDebuggerPresent() ) { - OutputDebugString("Principal: "); - OutputDebugString(pNCi[i]->principal); - OutputDebugString(" in ccache "); - OutputDebugString(pNCi[i]->name); - OutputDebugString("\n"); - } - if ( strcmp(pNCi[i]->name,pNCi[i]->principal) - && strcmp(pNCi[i]->name,LSA_CCNAME) - ) { - int found = 0; - for ( j=0; pNCi[j]; j++ ) { - if (!strcmp(pNCi[j]->name,pNCi[i]->principal)) { - found = 1; - break; - } - } - - code = pkrb5_cc_resolve(ctx, pNCi[i]->principal, &cc); - if (code) goto loop_cleanup; - - if (!found) { - krb5_ccache oldcc = 0; - - if ( IsDebuggerPresent() ) - OutputDebugString("copying ccache data to new ccache\n"); - - code = pkrb5_parse_name(ctx, pNCi[i]->principal, &principal); - if (code) goto loop_cleanup; - code = pkrb5_cc_initialize(ctx, cc, principal); - if (code) goto loop_cleanup; - - code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &oldcc); - if (code) goto loop_cleanup; - code = pkrb5_cc_copy_creds(ctx,oldcc,cc); - if (code) { - code = pkrb5_cc_close(ctx,cc); - cc = 0; - code = pkrb5_cc_close(ctx,oldcc); - cc = 0; - KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL); - continue; - } - code = pkrb5_cc_close(ctx,oldcc); - } - } else { - code = pkrb5_cc_resolve(ctx, pNCi[i]->name, &cc); - if (code) goto loop_cleanup; - } - - flags = 0; // turn off OPENCLOSE mode - code = pkrb5_cc_set_flags(ctx, cc, flags); - if ( code ) goto cleanup; - - KFW_AFS_update_princ_ccache_data(ctx, cc, !strcmp(pNCi[i]->name,LSA_CCNAME)); - - cc_code = pkrb5_cc_start_seq_get(ctx, cc, &cur); - - while (!(cc_code = pkrb5_cc_next_cred(ctx, cc, &cur, &creds))) { - krb5_data * sname = krb5_princ_name(ctx, creds.server); - krb5_data * cell = krb5_princ_component(ctx, creds.server, 1); - krb5_data * realm = krb5_princ_realm(ctx, creds.server); - if ( sname && cell && !strcmp("afs",sname->data) ) { - struct ktc_principal aserver; - struct ktc_principal aclient; - struct ktc_token atoken; - int active = TRUE; - - if ( IsDebuggerPresent() ) { - OutputDebugString("Found AFS ticket: "); - OutputDebugString(sname->data); - if ( cell->data ) { - OutputDebugString("/"); - OutputDebugString(cell->data); - } - OutputDebugString("@"); - OutputDebugString(realm->data); - OutputDebugString("\n"); - } - - memset(&aserver, '\0', sizeof(aserver)); - strcpy(aserver.name, sname->data); - strcpy(aserver.cell, cell->data); - - code = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient); - if (!code) { - // Found a token in AFS Client Server which matches - char pname[128], *p, *q; - for ( p=pname, q=aclient.name; *q; p++, q++) - *p = *q; - for ( *p++ = '@', q=aclient.cell; *q; p++, q++) - *p = toupper(*q); - *p = '\0'; - - if ( IsDebuggerPresent() ) { - OutputDebugString("Found AFS token: "); - OutputDebugString(pname); - OutputDebugString("\n"); - } - - if ( strcmp(pname,pNCi[i]->principal) ) - active = FALSE; - KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active); - } else { - // Attempt to import it - KFW_AFS_update_cell_princ_map(ctx, cell->data, pNCi[i]->principal, active); - - if ( IsDebuggerPresent() ) { - OutputDebugString("Calling KFW_AFS_klog() to obtain token\n"); - } - - code = KFW_AFS_klog(ctx, cc, "afs", cell->data, realm->data, pLeash_get_default_lifetime()); - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"KFW_AFS_klog() returns: %d\n",code); - OutputDebugString(message); - } - } - } else if ( IsDebuggerPresent() ) { - OutputDebugString("Found ticket: "); - OutputDebugString(sname->data); - if ( cell && cell->data ) { - OutputDebugString("/"); - OutputDebugString(cell->data); - } - OutputDebugString("@"); - OutputDebugString(realm->data); - OutputDebugString("\n"); - } - pkrb5_free_cred_contents(ctx, &creds); - } - - if (cc_code == KRB5_CC_END) { - cc_code = pkrb5_cc_end_seq_get(ctx, cc, &cur); - if (cc_code) goto loop_cleanup; - } - - loop_cleanup: - flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE - code = pkrb5_cc_set_flags(ctx, cc, flags); - if (cc) { - pkrb5_cc_close(ctx,cc); - cc = 0; - } - if (principal) { - pkrb5_free_principal(ctx,principal); - principal = 0; - } - } - - cleanup: - if (ctx) - pkrb5_free_context(ctx); - if (pNCi) - pcc_free_NC_info(cc_ctx, &pNCi); - if (cc_ctx) - pcc_shutdown(&cc_ctx); -} - - -int -KFW_AFS_get_cred(char * username, - char * instance, - char * cell, - char * password, - int lifetime, - char ** reasonP ) -{ - krb5_context ctx = 0; - krb5_ccache cc = 0; - char * realm = 0; - char ** realmlist = 0; - krb5_principal principal = 0; - char * pname = 0; - krb5_error_code code; - char local_cell[MAXCELLCHARS+1]; - char **cells = NULL; - int cell_count=0; - afsconf_cell cellconfig; - - if (!pkrb5_init_context) - return 0; - - if ( IsDebuggerPresent() ) { - OutputDebugString("KFW_AFS_get_cred for token "); - OutputDebugString(username); - if ( instance ) { - OutputDebugString("/"); - OutputDebugString(instance); - } - OutputDebugString("@"); - OutputDebugString(cell); - OutputDebugString("\n"); - } - - code = pkrb5_init_context(&ctx); - if ( code ) goto cleanup; - - code = get_cellconfig( cell, (void*)&cellconfig, local_cell); - if ( code ) goto cleanup; - - realm = strchr(username,'@'); - if (realm) { - *realm = '\0'; - realm++; - } - if ( !realm || !realm[0] ) - realm = afs_realm_of_cell(&cellconfig); // do not free - - if ( IsDebuggerPresent() ) { - OutputDebugString("Realm: "); - OutputDebugString(realm); - OutputDebugString("\n"); - } - - code = pkrb5_build_principal(ctx, &principal, strlen(realm), - realm, username, - (instance && instance[0]) ? instance : NULL, - NULL); - - code = KFW_get_ccache(ctx, principal, &cc); - if ( code ) goto cleanup; - - code = pkrb5_unparse_name(ctx, principal, &pname); - if ( code ) goto cleanup; - - if ( lifetime == 0 ) - lifetime = pLeash_get_default_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()); - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"KFW_kinit() returns: %d\n",code); - OutputDebugString(message); - } - if ( code ) goto cleanup; - - KFW_AFS_update_princ_ccache_data(ctx, cc, FALSE); - - code = KFW_AFS_klog(ctx, cc, "afs", cell, realm, lifetime); - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"KFW_AFS_klog() returns: %d\n",code); - OutputDebugString(message); - } - if ( code ) goto cleanup; - - KFW_AFS_update_cell_princ_map(ctx, cell, pname, TRUE); - - // Attempt to obtain new tokens for other cells supported by the same - // principal - cell_count = KFW_AFS_find_cells_for_princ(ctx, pname, &cells, TRUE); - if ( cell_count > 1 ) { - while ( cell_count-- ) { - if ( strcmp(cells[cell_count],cell) ) { - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"found another cell for the same principal: %s\n",cell); - OutputDebugString(message); - } - code = get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell); - if ( code ) continue; - - realm = afs_realm_of_cell(&cellconfig); // do not free - if ( IsDebuggerPresent() ) { - OutputDebugString("Realm: "); - OutputDebugString(realm); - OutputDebugString("\n"); - } - - code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], realm, lifetime); - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"KFW_AFS_klog() returns: %d\n",code); - OutputDebugString(message); - } - } - free(cells[cell_count]); - } - free(cells); - } else if ( cell_count == 1 ) { - free(cells[0]); - free(cells); - } - - cleanup: - if ( pname ) - pkrb5_free_unparsed_name(ctx,pname); - if ( cc ) - pkrb5_cc_close(ctx, cc); - - if ( code && reasonP ) { - *reasonP = (char *)perror_message(code); - } - return(code); -} - -int -KFW_AFS_destroy_tickets_for_cell(char * cell) -{ - krb5_context ctx = 0; - krb5_error_code code; - int count; - char ** principals = NULL; - - if (!pkrb5_init_context) - return 0; - - if ( IsDebuggerPresent() ) { - OutputDebugString("KFW_AFS_destroy_ticets_for_cell: "); - OutputDebugString(cell); - OutputDebugString("\n"); - } - - code = pkrb5_init_context(&ctx); - if (code) ctx = 0; - - count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, FALSE); - if ( count > 0 ) { - krb5_principal princ = 0; - krb5_ccache cc = 0; - - while ( count-- ) { - int cell_count = KFW_AFS_find_cells_for_princ(ctx, principals[count], NULL, TRUE); - if ( cell_count > 1 ) { - // TODO - What we really should do here is verify whether or not any of the - // other cells which use this principal to obtain its credentials actually - // have valid tokens or not. If they are currently using these credentials - // we will skip them. For the time being we assume that if there is an active - // map in the table that they are actively being used. - goto loop_cleanup; - } - - code = pkrb5_parse_name(ctx, principals[count], &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; - } - - KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], FALSE); - free(principals[count]); - } - free(principals); - } - pkrb5_free_context(ctx); - return 0; -} - -int -KFW_AFS_renew_expiring_tokens(void) -{ - krb5_error_code code = 0; - krb5_context ctx = 0; - krb5_ccache cc = 0; - krb5_timestamp now; - struct principal_ccache_data * pcc_next = princ_cc_data; - int cell_count; - char ** cells=NULL; - const char * realm = NULL; - char local_cell[MAXCELLCHARS+1]=""; - afsconf_cell cellconfig; - - if (!pkrb5_init_context) - return 0; - - if ( pcc_next == NULL ) // nothing to do - return 0; - - if ( IsDebuggerPresent() ) { - OutputDebugString("KFW_AFS_renew_expiring_tokens\n"); - } - - code = pkrb5_init_context(&ctx); - if (code) goto cleanup; - - code = pkrb5_timeofday(ctx, &now); - if (code) goto cleanup; - - for ( ; pcc_next ; pcc_next = pcc_next->next ) { - if ( pcc_next->expired ) - continue; - - if ( now >= (pcc_next->expiration_time) ) { - if ( !pcc_next->from_lsa ) { - pcc_next->expired = 1; - continue; - } - } - - if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) { - code = pkrb5_cc_resolve(ctx, pcc_next->ccache_name, &cc); - if ( code ) - goto loop_cleanup; - code = KFW_renew(ctx,cc); -#ifdef USE_MS2MIT - if ( code && pcc_next->from_lsa) - goto loop_cleanup; -#endif /* USE_MS2MIT */ - - - KFW_AFS_update_princ_ccache_data(ctx, cc, pcc_next->from_lsa); - if (code) goto loop_cleanup; - - // Attempt to obtain new tokens for other cells supported by the same - // principal - cell_count = KFW_AFS_find_cells_for_princ(ctx, pcc_next->principal, &cells, TRUE); - if ( cell_count > 0 ) { - while ( cell_count-- ) { - if ( IsDebuggerPresent() ) { - OutputDebugString("Cell: "); - OutputDebugString(cells[cell_count]); - OutputDebugString("\n"); - } - code = get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell); - if ( code ) continue; - realm = afs_realm_of_cell(&cellconfig); // do not free - if ( IsDebuggerPresent() ) { - OutputDebugString("Realm: "); - OutputDebugString(realm); - OutputDebugString("\n"); - } - code = KFW_AFS_klog(ctx, cc, "afs", cells[cell_count], (char *)realm, pLeash_get_default_lifetime()); - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"KFW_AFS_klog() returns: %d\n",code); - OutputDebugString(message); - } - free(cells[cell_count]); - } - free(cells); - } - } - - loop_cleanup: - if ( cc ) { - pkrb5_cc_close(ctx,cc); - cc = 0; - } - } - - cleanup: - if ( cc ) - pkrb5_cc_close(ctx,cc); - if ( ctx ) - pkrb5_free_context(ctx); - - return 0; -} - - -BOOL -KFW_AFS_renew_token_for_cell(char * cell) -{ - krb5_error_code code = 0; - krb5_context ctx = 0; - int count; - char ** principals = NULL; - - if (!pkrb5_init_context) - return 0; - - if ( IsDebuggerPresent() ) { - OutputDebugString("KFW_AFS_renew_token_for_cell:"); - OutputDebugString(cell); - OutputDebugString("\n"); - } - - code = pkrb5_init_context(&ctx); - if (code) goto cleanup; - - count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE); - if ( count == 0 ) { - // We know we must have a credential somewhere since we are - // trying to renew a token - - KFW_import_ccache_data(); - count = KFW_AFS_find_principals_for_cell(ctx, cell, &principals, TRUE); - } - if ( count > 0 ) { - krb5_principal princ = 0; - krb5_principal service = 0; -#ifdef COMMENT - krb5_creds mcreds, creds; -#endif /* COMMENT */ - krb5_ccache cc = 0; - const char * realm = NULL; - afsconf_cell cellconfig; - char local_cell[MAXCELLCHARS+1]; - - while ( count-- ) { - code = pkrb5_parse_name(ctx, principals[count], &princ); - if (code) goto loop_cleanup; - - code = KFW_get_ccache(ctx, princ, &cc); - if (code) goto loop_cleanup; - - code = get_cellconfig( cell, (void*)&cellconfig, local_cell); - if ( code ) goto loop_cleanup; - - realm = afs_realm_of_cell(&cellconfig); // do not free - if ( IsDebuggerPresent() ) { - OutputDebugString("Realm: "); - OutputDebugString(realm); - OutputDebugString("\n"); - } - -#ifdef COMMENT - /* krb5_cc_remove_cred() is not implemented - * for a single cred - */ - code = pkrb5_build_principal(ctx, &service, strlen(realm), - realm, "afs", cell, NULL); - if (!code) { - memset(&mcreds, 0, sizeof(krb5_creds)); - mcreds.client = princ; - mcreds.server = service; - - code = pkrb5_cc_retrieve_cred(ctx, cc, 0, &mcreds, &creds); - if (!code) { - if ( IsDebuggerPresent() ) { - char * cname, *sname; - pkrb5_unparse_name(ctx, creds.client, &cname); - pkrb5_unparse_name(ctx, creds.server, &sname); - OutputDebugString("Removing credential for client \""); - OutputDebugString(cname); - OutputDebugString("\" and service \""); - OutputDebugString(sname); - OutputDebugString("\"\n"); - pkrb5_free_unparsed_name(ctx,cname); - pkrb5_free_unparsed_name(ctx,sname); - } - - code = pkrb5_cc_remove_cred(ctx, cc, 0, &creds); - pkrb5_free_principal(ctx, creds.client); - pkrb5_free_principal(ctx, creds.server); - } - } -#endif /* COMMENT */ - - code = KFW_AFS_klog(ctx, cc, "afs", cell, (char *)realm, pLeash_get_default_lifetime()); - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"KFW_AFS_klog() returns: %d\n",code); - OutputDebugString(message); - } - - loop_cleanup: - if (cc) { - pkrb5_cc_close(ctx, cc); - cc = 0; - } - if (princ) { - pkrb5_free_principal(ctx, princ); - princ = 0; - } - if (service) { - pkrb5_free_principal(ctx, service); - princ = 0; - } - - KFW_AFS_update_cell_princ_map(ctx, cell, principals[count], code ? FALSE : TRUE); - free(principals[count]); - } - free(principals); - } else - code = -1; // we did not renew the tokens - - cleanup: - pkrb5_free_context(ctx); - return (code ? FALSE : TRUE); - -} - -int -KFW_AFS_renew_tokens_for_all_cells(void) -{ - struct cell_principal_map * next = cell_princ_map; - - if ( IsDebuggerPresent() ) - OutputDebugString("KFW_AFS_renew_tokens_for_all()\n"); - - if ( !next ) - return 0; - - for ( ; next ; next = next->next ) { - if ( next->active ) - KFW_AFS_renew_token_for_cell(next->cell); - } - return 0; -} - -int -KFW_renew(krb5_context alt_ctx, krb5_ccache alt_cc) -{ - krb5_error_code code = 0; - krb5_context ctx = 0; - krb5_ccache cc = 0; - krb5_principal me = 0; - krb5_principal server = 0; - krb5_creds my_creds; - krb5_data *realm = 0; - - if (!pkrb5_init_context) - return 0; - - memset(&my_creds, 0, sizeof(krb5_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_cc_get_principal(ctx, cc, &me); - if (code) goto cleanup; - - realm = krb5_princ_realm(ctx, me); - - code = pkrb5_build_principal_ext(ctx, &server, - realm->length,realm->data, - KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME, - realm->length,realm->data, - 0); - if ( code ) - goto cleanup; - - if ( IsDebuggerPresent() ) { - char * cname, *sname; - pkrb5_unparse_name(ctx, me, &cname); - pkrb5_unparse_name(ctx, server, &sname); - OutputDebugString("Renewing credential for client \""); - OutputDebugString(cname); - OutputDebugString("\" and service \""); - OutputDebugString(sname); - OutputDebugString("\"\n"); - pkrb5_free_unparsed_name(ctx,cname); - pkrb5_free_unparsed_name(ctx,sname); - } - - my_creds.client = me; - my_creds.server = server; - - code = pkrb5_get_renewed_creds(ctx, &my_creds, me, cc, NULL); - if (code) { - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"krb5_get_renewed_creds() failed: %d\n",code); - OutputDebugString(message); - } - goto cleanup; - } - - code = pkrb5_cc_initialize(ctx, cc, me); - if (code) { - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"krb5_cc_initialize() failed: %d\n",code); - OutputDebugString(message); - } - goto cleanup; - } - - code = pkrb5_cc_store_cred(ctx, cc, &my_creds); - if (code) { - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"krb5_cc_store_cred() failed: %d\n",code); - OutputDebugString(message); - } - goto cleanup; - } - - cleanup: - if (my_creds.client == me) - my_creds.client = 0; - if (my_creds.server == server) - my_creds.server = 0; - pkrb5_free_cred_contents(ctx, &my_creds); - if (me) - pkrb5_free_principal(ctx, me); - if (server) - pkrb5_free_principal(ctx, server); - if (cc && (cc != alt_cc)) - pkrb5_cc_close(ctx, cc); - 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(); - else - lifetime *= 5*60; - - if (renew_life > 0) - renew_life *= 5*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) - { - // we are going to add the public IP address specified by the user - // to the list provided by the operating system - 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); /* safe */ - 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, // password - KRB5_prompter, // prompter - hParent, // prompter data - 0, // start time - 0, // service name - &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;icontents ) - 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_kdestroy(krb5_context alt_ctx, krb5_ccache alt_cc) -{ - krb5_context ctx; - krb5_ccache cc; - 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 ( alt_cc ) { - cc = alt_cc; - } else { - code = pkrb5_cc_default(ctx, &cc); - if (code) goto cleanup; - } - - code = pkrb5_cc_destroy(ctx, cc); - if ( !code ) cc = 0; - - cleanup: - if (cc && (cc != alt_cc)) - pkrb5_cc_close(ctx, cc); - if (ctx && (ctx != alt_ctx)) - pkrb5_free_context(ctx); - - return(code); -} - - -#ifdef USE_MS2MIT -static BOOL -GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData) -{ - NTSTATUS Status = 0; - HANDLE TokenHandle; - TOKEN_STATISTICS Stats; - DWORD ReqLen; - BOOL Success; - - if (!ppSessionData) - return FALSE; - *ppSessionData = NULL; - - Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle ); - if ( !Success ) - return FALSE; - - Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen ); - CloseHandle( TokenHandle ); - if ( !Success ) - return FALSE; - - Status = pLsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData ); - if ( FAILED(Status) || !ppSessionData ) - return FALSE; - - return TRUE; -} - -// -// MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the -// cache. It validates whether or not it is reasonable to assume that if we -// attempted to retrieve valid tickets we could do so. Microsoft does not -// automatically renew expired tickets. Therefore, the cache could contain -// expired or invalid tickets. Microsoft also caches the user's password -// and will use it to retrieve new TGTs if the cache is empty and tickets -// are requested. - -static BOOL -MSLSA_IsKerberosLogon(VOID) -{ - PSECURITY_LOGON_SESSION_DATA pSessionData = NULL; - BOOL Success = FALSE; - - if ( GetSecurityLogonSessionData(&pSessionData) ) { - if ( pSessionData->AuthenticationPackage.Buffer ) { - WCHAR buffer[256]; - WCHAR *usBuffer; - int usLength; - - Success = FALSE; - usBuffer = (pSessionData->AuthenticationPackage).Buffer; - usLength = (pSessionData->AuthenticationPackage).Length; - if (usLength < 256) - { - lstrcpynW (buffer, usBuffer, usLength); - lstrcatW (buffer,L""); - if ( !lstrcmpW(L"Kerberos",buffer) ) - Success = TRUE; - } - } - pLsaFreeReturnBuffer(pSessionData); - } - return Success; -} -#endif /* USE_MS2MIT */ - -static BOOL CALLBACK -MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam) -{ - int i; - - switch ( message ) { - case WM_INITDIALOG: - if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT ) - { - SetFocus(GetDlgItem( hDialog, ID_MID_TEXT)); - return FALSE; - } - for ( i=0; i < mid_cnt ; i++ ) { - if (mid_tb[i].echo == 0) - SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0); - else if (mid_tb[i].echo == 2) - SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0); - } - return TRUE; - - case WM_COMMAND: - switch ( LOWORD(wParam) ) { - case IDOK: - for ( i=0; i < mid_cnt ; i++ ) { - if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) ) - *mid_tb[i].buf = '\0'; - } - /* fallthrough */ - case IDCANCEL: - EndDialog(hDialog, LOWORD(wParam)); - return TRUE; - } - } - return FALSE; -} - -static LPWORD -lpwAlign( LPWORD lpIn ) -{ - ULONG ul; - - ul = (ULONG) lpIn; - ul += 3; - ul >>=2; - ul <<=2; - return (LPWORD) ul;; -} - -/* - * dialog widths are measured in 1/4 character widths - * dialog height are measured in 1/8 character heights - */ - -static LRESULT -MultiInputDialog( HINSTANCE hinst, HWND hwndOwner, - char * ptext[], int numlines, int width, - int tb_cnt, struct textField * tb) -{ - HGLOBAL hgbl; - LPDLGTEMPLATE lpdt; - LPDLGITEMTEMPLATE lpdit; - LPWORD lpw; - LPWSTR lpwsz; - LRESULT ret; - int nchar, i, pwid; - - hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096); - if (!hgbl) - return -1; - - mid_cnt = tb_cnt; - mid_tb = tb; - - lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl); - - // Define a dialog box. - - lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU - | DS_MODALFRAME | WS_CAPTION | DS_CENTER - | DS_SETFOREGROUND | DS_3DLOOK - | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE; - lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls - lpdt->x = 10; - lpdt->y = 10; - lpdt->cx = 20 + width * 4; - lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14; - - lpw = (LPWORD) (lpdt + 1); - *lpw++ = 0; // no menu - *lpw++ = 0; // predefined dialog box class (by default) - - lpwsz = (LPWSTR) lpw; - nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128); - lpw += nchar; - *lpw++ = 8; // font size (points) - lpwsz = (LPWSTR) lpw; - nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg", - -1, lpwsz, 128); - lpw += nchar; - - //----------------------- - // Define an OK button. - //----------------------- - lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary - lpdit = (LPDLGITEMTEMPLATE) lpw; - lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER; - lpdit->dwExtendedStyle = 0; - lpdit->x = (lpdt->cx - 14)/4 - 20; - lpdit->y = 10 + (numlines + tb_cnt + 2) * 14; - lpdit->cx = 40; - lpdit->cy = 14; - lpdit->id = IDOK; // OK button identifier - - lpw = (LPWORD) (lpdit + 1); - *lpw++ = 0xFFFF; - *lpw++ = 0x0080; // button class - - lpwsz = (LPWSTR) lpw; - nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50); - lpw += nchar; - *lpw++ = 0; // no creation data - - //----------------------- - // Define an Cancel button. - //----------------------- - lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary - lpdit = (LPDLGITEMTEMPLATE) lpw; - lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER; - lpdit->dwExtendedStyle = 0; - lpdit->x = (lpdt->cx - 14)*3/4 - 20; - lpdit->y = 10 + (numlines + tb_cnt + 2) * 14; - lpdit->cx = 40; - lpdit->cy = 14; - lpdit->id = IDCANCEL; // CANCEL button identifier - - lpw = (LPWORD) (lpdit + 1); - *lpw++ = 0xFFFF; - *lpw++ = 0x0080; // button class - - lpwsz = (LPWSTR) lpw; - nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50); - lpw += nchar; - *lpw++ = 0; // no creation data - - /* Add controls for preface data */ - for ( i=0; istyle = WS_CHILD | WS_VISIBLE | SS_LEFT; - lpdit->dwExtendedStyle = 0; - lpdit->x = 10; - lpdit->y = 10 + i * 14; - lpdit->cx = strlen(ptext[i]) * 4 + 10; - lpdit->cy = 14; - lpdit->id = ID_TEXT + i; // text identifier - - lpw = (LPWORD) (lpdit + 1); - *lpw++ = 0xFFFF; - *lpw++ = 0x0082; // static class - - lpwsz = (LPWSTR) lpw; - nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i], - -1, lpwsz, 2*width); - lpw += nchar; - *lpw++ = 0; // no creation data - } - - for ( i=0, pwid = 0; istyle = WS_CHILD | WS_VISIBLE | SS_LEFT; - lpdit->dwExtendedStyle = 0; - lpdit->x = 10; - lpdit->y = 10 + (numlines + i + 1) * 14; - lpdit->cx = pwid * 4; - lpdit->cy = 14; - lpdit->id = ID_TEXT + numlines + i; // text identifier - - lpw = (LPWORD) (lpdit + 1); - *lpw++ = 0xFFFF; - *lpw++ = 0x0082; // static class - - lpwsz = (LPWSTR) lpw; - nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "", - -1, lpwsz, 128); - lpw += nchar; - *lpw++ = 0; // no creation data - - /*----------------------- - * Define an edit control. - *-----------------------*/ - lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */ - lpdit = (LPDLGITEMTEMPLATE) lpw; - lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD); - lpdit->dwExtendedStyle = 0; - lpdit->x = 10 + (pwid + 1) * 4; - lpdit->y = 10 + (numlines + i + 1) * 14; - lpdit->cx = (width - (pwid + 1)) * 4; - lpdit->cy = 14; - lpdit->id = ID_MID_TEXT + i; // identifier - - lpw = (LPWORD) (lpdit + 1); - *lpw++ = 0xFFFF; - *lpw++ = 0x0081; // edit class - - lpwsz = (LPWSTR) lpw; - nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "", - -1, lpwsz, 128); - lpw += nchar; - *lpw++ = 0; // no creation data - } - - GlobalUnlock(hgbl); - ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl, - hwndOwner, (DLGPROC) MultiInputDialogProc); - GlobalFree(hgbl); - - switch ( ret ) { - case 0: /* Timeout */ - return -1; - case IDOK: - return 1; - case IDCANCEL: - return 0; - default: { - char buf[256]; - sprintf(buf,"DialogBoxIndirect() failed: %d",GetLastError()); - MessageBox(hwndOwner, - buf, - "GetLastError()", - MB_OK | MB_ICONINFORMATION | MB_TASKMODAL); - return -1; - } - } -} - -static int -multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[]) -{ - HINSTANCE hInst = 0; - int maxwidth = 0; - int numlines = 0; - int len; - char * plines[16], *p = preface ? preface : ""; - int i; - - for ( i=0; i<16; i++ ) - plines[i] = NULL; - - while (*p && numlines < 16) { - plines[numlines++] = p; - for ( ;*p && *p != '\r' && *p != '\n'; p++ ); - if ( *p == '\r' && *(p+1) == '\n' ) { - *p++ = '\0'; - p++; - } else if ( *p == '\n' ) { - *p++ = '\0'; - } - if ( strlen(plines[numlines-1]) > maxwidth ) - maxwidth = strlen(plines[numlines-1]); - } - - for ( i=0;i 40 ? 40 : tb[i].len); - if ( maxwidth < len ) - maxwidth = len; - } - - return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)); -} - -static krb5_error_code KRB5_CALLCONV -KRB5_prompter( krb5_context context, - void *data, - const char *name, - const char *banner, - int num_prompts, - krb5_prompt prompts[]) -{ - krb5_error_code errcode = 0; - int i; - struct textField * tb = NULL; - int len = 0, blen=0, nlen=0; - HWND hParent = (HWND)data; - - if (name) - nlen = strlen(name)+2; - - if (banner) - blen = strlen(banner)+2; - - tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts); - if ( tb != NULL ) { - int ok; - memset(tb,0,sizeof(struct textField) * num_prompts); - for ( i=0; i < num_prompts; i++ ) { - tb[i].buf = prompts[i].reply->data; - tb[i].len = prompts[i].reply->length; - tb[i].label = prompts[i].prompt; - tb[i].def = NULL; - tb[i].echo = (prompts[i].hidden ? 2 : 1); - } - - ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb); - if ( ok ) { - for ( i=0; i < num_prompts; i++ ) - prompts[i].reply->length = strlen(prompts[i].reply->data); - } else - errcode = -2; - } - - if ( tb ) - free(tb); - if (errcode) { - for (i = 0; i < num_prompts; i++) { - memset(prompts[i].reply->data, 0, prompts[i].reply->length); - } - } - return errcode; -} - -BOOL -KFW_AFS_wait_for_service_start(void) -{ - char HostName[64]; - DWORD CurrentState; - - CurrentState = SERVICE_START_PENDING; - memset(HostName, '\0', sizeof(HostName)); - gethostname(HostName, sizeof(HostName)); - - while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED) - { - if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) - return(0); - if ( IsDebuggerPresent() ) { - switch ( CurrentState ) { - case SERVICE_STOPPED: - OutputDebugString("SERVICE_STOPPED\n"); - break; - case SERVICE_START_PENDING: - OutputDebugString("SERVICE_START_PENDING\n"); - break; - case SERVICE_STOP_PENDING: - OutputDebugString("SERVICE_STOP_PENDING\n"); - break; - case SERVICE_RUNNING: - OutputDebugString("SERVICE_RUNNING\n"); - break; - case SERVICE_CONTINUE_PENDING: - OutputDebugString("SERVICE_CONTINUE_PENDING\n"); - break; - case SERVICE_PAUSE_PENDING: - OutputDebugString("SERVICE_PAUSE_PENDING\n"); - break; - case SERVICE_PAUSED: - OutputDebugString("SERVICE_PAUSED\n"); - break; - default: - OutputDebugString("UNKNOWN Service State\n"); - } - } - if (CurrentState == SERVICE_STOPPED) - return(0); - if (CurrentState == SERVICE_RUNNING) - return(1); - Sleep(500); - } - return(0); -} - - -int -KFW_AFS_unlog(void) -{ - long rc; - char HostName[64]; - DWORD CurrentState; - - CurrentState = 0; - memset(HostName, '\0', sizeof(HostName)); - gethostname(HostName, sizeof(HostName)); - if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) - return(0); - if (CurrentState != SERVICE_RUNNING) - return(0); - - rc = pktc_ForgetAllTokens(); - - return(0); -} - -int -KFW_AFS_klog( - krb5_context alt_ctx, - krb5_ccache alt_cc, - char *service, - char *cell, - char *realm, - int LifeTime - ) -{ - long rc = 0; - CREDENTIALS creds; - KTEXT_ST ticket; - struct ktc_principal aserver; - struct ktc_principal aclient; - char realm_of_user[REALM_SZ]; /* Kerberos realm of user */ - char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */ - char local_cell[MAXCELLCHARS+1]; - char Dmycell[MAXCELLCHARS+1]; - struct ktc_token atoken; - struct ktc_token btoken; - afsconf_cell ak_cellconfig; /* General information about the cell */ - char RealmName[128]; - char CellName[128]; - char ServiceName[128]; - DWORD CurrentState; - char HostName[64]; - BOOL try_krb5 = 0; - krb5_context ctx = 0; - krb5_ccache cc = 0; - krb5_creds increds; - krb5_creds * k5creds = 0; - krb5_error_code code; - krb5_principal client_principal = 0; - char * cname = 0, *sname = 0; - int i, retry = 0; - - CurrentState = 0; - memset(HostName, '\0', sizeof(HostName)); - gethostname(HostName, sizeof(HostName)); - if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) { - if ( IsDebuggerPresent() ) - OutputDebugString("Unable to retrieve AFSD Service Status\n"); - return(-1); - } - if (CurrentState != SERVICE_RUNNING) { - if ( IsDebuggerPresent() ) - OutputDebugString("AFSD Service NOT RUNNING\n"); - return(-2); - } - - if (!pkrb5_init_context) - return 0; - - memset(RealmName, '\0', sizeof(RealmName)); - memset(CellName, '\0', sizeof(CellName)); - memset(ServiceName, '\0', sizeof(ServiceName)); - memset(realm_of_user, '\0', sizeof(realm_of_user)); - memset(realm_of_cell, '\0', sizeof(realm_of_cell)); - if (cell && cell[0]) - strcpy(Dmycell, cell); - else - memset(Dmycell, '\0', sizeof(Dmycell)); - - // NULL or empty cell returns information on local cell - if (rc = get_cellconfig(Dmycell, &ak_cellconfig, local_cell)) - { - // KFW_AFS_error(rc, "get_cellconfig()"); - return(rc); - } - - 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 skip_krb5_init; - } - - memset((char *)&increds, 0, sizeof(increds)); - - code = pkrb5_cc_get_principal(ctx, cc, &client_principal); - if (code) { - if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() ) - { - OutputDebugString("Principal Not Found for ccache\n"); - } - goto skip_krb5_init; - } - i = krb5_princ_realm(ctx, client_principal)->length; - if (i > REALM_SZ-1) - i = REALM_SZ-1; - strncpy(realm_of_user,krb5_princ_realm(ctx, client_principal)->data,i); - realm_of_user[i] = 0; - try_krb5 = 1; - - skip_krb5_init: -#ifdef USE_KRB4 - if ( !try_krb5 || !realm_of_user[0] ) { - if ((rc = (*pkrb_get_tf_realm)((*ptkt_string)(), realm_of_user)) != KSUCCESS) - { - goto cleanup; - } - } -#else - goto cleanup; -#endif - strcpy(realm_of_cell, afs_realm_of_cell(&ak_cellconfig)); - - if (strlen(service) == 0) - strcpy(ServiceName, "afs"); - else - strcpy(ServiceName, service); - - if (strlen(cell) == 0) - strcpy(CellName, local_cell); - else - strcpy(CellName, cell); - - if (strlen(realm) == 0) - strcpy(RealmName, realm_of_cell); - else - strcpy(RealmName, realm); - - memset(&creds, '\0', sizeof(creds)); - - if ( try_krb5 ) { - int i, len; - char *p; - - /* First try service/cell@REALM */ - if (code = pkrb5_build_principal(ctx, &increds.server, - strlen(RealmName), - RealmName, - ServiceName, - CellName, - 0)) - { - goto cleanup; - } - - increds.client = client_principal; - increds.times.endtime = 0; - /* Ask for DES since that is what V4 understands */ - increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; - - - if ( IsDebuggerPresent() ) { - pkrb5_unparse_name(ctx, increds.client, &cname); - pkrb5_unparse_name(ctx, increds.server, &sname); - OutputDebugString("Getting tickets for \""); - OutputDebugString(cname); - OutputDebugString("\" and service \""); - OutputDebugString(sname); - OutputDebugString("\"\n"); - cname = sname = 0; - } - - code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); - if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || - code == KRB5KRB_ERR_GENERIC /* heimdal */ || - code == KRB5KRB_AP_ERR_MSG_TYPE) { - /* Or service@REALM */ - pkrb5_free_principal(ctx,increds.server); - increds.server = 0; - code = pkrb5_build_principal(ctx, &increds.server, - strlen(RealmName), - RealmName, - ServiceName, - 0); - - if ( IsDebuggerPresent() ) { - char * cname, *sname; - pkrb5_unparse_name(ctx, increds.client, &cname); - pkrb5_unparse_name(ctx, increds.server, &sname); - OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n"); - OutputDebugString("Trying again: getting tickets for \""); - OutputDebugString(cname); - OutputDebugString("\" and service \""); - OutputDebugString(sname); - OutputDebugString("\"\n"); - pkrb5_free_unparsed_name(ctx,cname); - pkrb5_free_unparsed_name(ctx,sname); - cname = sname = 0; - } - - if (!code) - code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); - } - - if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || - code == KRB5KRB_ERR_GENERIC /* heimdal */ || - code == KRB5KRB_AP_ERR_MSG_TYPE) && - strcmp(RealmName, realm_of_cell)) { - /* Or service/cell@REALM_OF_CELL */ - strcpy(RealmName, realm_of_cell); - pkrb5_free_principal(ctx,increds.server); - increds.server = 0; - code = pkrb5_build_principal(ctx, &increds.server, - strlen(RealmName), - RealmName, - ServiceName, - CellName, - 0); - - if ( IsDebuggerPresent() ) { - char * cname, *sname; - pkrb5_unparse_name(ctx, increds.client, &cname); - pkrb5_unparse_name(ctx, increds.server, &sname); - OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n"); - OutputDebugString("Trying again: getting tickets for \""); - OutputDebugString(cname); - OutputDebugString("\" and service \""); - OutputDebugString(sname); - OutputDebugString("\"\n"); - pkrb5_free_unparsed_name(ctx,cname); - pkrb5_free_unparsed_name(ctx,sname); - cname = sname = 0; - } - - if (!code) - code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); - - - if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || - code == KRB5KRB_ERR_GENERIC /* heimdal */ || - code == KRB5KRB_AP_ERR_MSG_TYPE) { - /* Or service@REALM_OF_CELL */ - pkrb5_free_principal(ctx,increds.server); - increds.server = 0; - code = pkrb5_build_principal(ctx, &increds.server, - strlen(RealmName), - RealmName, - ServiceName, - 0); - - if ( IsDebuggerPresent() ) { - char * cname, *sname; - pkrb5_unparse_name(ctx, increds.client, &cname); - pkrb5_unparse_name(ctx, increds.server, &sname); - OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n"); - OutputDebugString("Trying again: getting tickets for \""); - OutputDebugString(cname); - OutputDebugString("\" and service \""); - OutputDebugString(sname); - OutputDebugString("\"\n"); - pkrb5_free_unparsed_name(ctx,cname); - pkrb5_free_unparsed_name(ctx,sname); - cname = sname = 0; - } - - if (!code) - code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); - } - } - - if (code) { - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"krb5_get_credentials returns: %d\n",code); - OutputDebugString(message); - } - try_krb5 = 0; - goto use_krb4; - } - - /* This code inserts the entire K5 ticket into the token - * No need to perform a krb524 translation which is - * commented out in the code below - */ - if (k5creds->ticket.length > MAXKTCTICKETLEN) - goto try_krb524d; - - memset(&aserver, '\0', sizeof(aserver)); - strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1); - strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1); - - memset(&atoken, '\0', sizeof(atoken)); - atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5; - atoken.startTime = k5creds->times.starttime; - atoken.endTime = k5creds->times.endtime; - memcpy(&atoken.sessionKey, k5creds->keyblock.contents, k5creds->keyblock.length); - atoken.ticketLen = k5creds->ticket.length; - memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen); - - retry_gettoken5: - rc = pktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient); - if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) { - if ( rc == KTC_NOCM && retry < 20 ) { - Sleep(500); - retry++; - goto retry_gettoken5; - } - goto try_krb524d; - } - - if (atoken.kvno == btoken.kvno && - atoken.ticketLen == btoken.ticketLen && - !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) && - !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) - { - /* Success - Nothing to do */ - goto cleanup; - } - - // * Reset the "aclient" structure before we call ktc_SetToken. - // * This structure was first set by the ktc_GetToken call when - // * we were comparing whether identical tokens already existed. - - len = min(k5creds->client->data[0].length,MAXKTCNAMELEN - 1); - strncpy(aclient.name, k5creds->client->data[0].data, len); - aclient.name[len] = '\0'; - - if ( k5creds->client->length > 1 ) { - char * p; - strcat(aclient.name, "."); - p = aclient.name + strlen(aclient.name); - len = min(k5creds->client->data[1].length,MAXKTCNAMELEN - strlen(aclient.name) - 1); - strncpy(p, k5creds->client->data[1].data, len); - p[len] = '\0'; - } - aclient.instance[0] = '\0'; - - strcpy(aclient.cell, realm_of_cell); - - len = min(k5creds->client->realm.length,strlen(realm_of_cell)); - if ( strncmp(realm_of_cell, k5creds->client->realm.data, len) ) { - char * p; - strcat(aclient.name, "@"); - p = aclient.name + strlen(aclient.name); - len = min(k5creds->client->realm.length,MAXKTCNAMELEN - strlen(aclient.name) - 1); - strncpy(p, k5creds->client->realm.data, len); - p[len] = '\0'; - } - - aclient.smbname[0] = '\0'; - - rc = pktc_SetToken(&aserver, &atoken, &aclient, 0); - if (!rc) - goto cleanup; /* We have successfully inserted the token */ - - try_krb524d: - /* Otherwise, the ticket could have been too large so try to - * convert using the krb524d running with the KDC - */ - code = pkrb524_convert_creds_kdc(ctx, k5creds, &creds); - pkrb5_free_creds(ctx, k5creds); - if (code) { - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"krb524_convert_creds_kdc returns: %d\n",code); - OutputDebugString(message); - } - try_krb5 = 0; - goto use_krb4; - } - } else { - use_krb4: -#ifdef USE_KRB4 - code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds); - if (code == NO_TKT_FIL) { - // if the problem is that we have no krb4 tickets - // do not attempt to continue - goto cleanup; - } - if (code != KSUCCESS) - code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds); - - if (code != KSUCCESS) - { - if ((code = (*pkrb_mk_req)(&ticket, ServiceName, CellName, RealmName, 0)) == KSUCCESS) - { - if ((code = (*pkrb_get_cred)(ServiceName, CellName, RealmName, &creds)) != KSUCCESS) - { - goto cleanup; - } - } - else if ((code = (*pkrb_mk_req)(&ticket, ServiceName, "", RealmName, 0)) == KSUCCESS) - { - if ((code = (*pkrb_get_cred)(ServiceName, "", RealmName, &creds)) != KSUCCESS) - { - goto cleanup; - } - } - else - { - goto cleanup; - } - } -#else - goto cleanup; -#endif - } - - memset(&aserver, '\0', sizeof(aserver)); - strncpy(aserver.name, ServiceName, MAXKTCNAMELEN - 1); - strncpy(aserver.cell, CellName, MAXKTCREALMLEN - 1); - - memset(&atoken, '\0', sizeof(atoken)); - atoken.kvno = creds.kvno; - atoken.startTime = creds.issue_date; - atoken.endTime = creds.issue_date + life_to_time(0,creds.lifetime); - memcpy(&atoken.sessionKey, creds.session, 8); - atoken.ticketLen = creds.ticket_st.length; - memcpy(atoken.ticket, creds.ticket_st.dat, atoken.ticketLen); - - retry_gettoken: - rc = pktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient); - if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) { - if ( rc == KTC_NOCM && retry < 20 ) { - Sleep(500); - retry++; - goto retry_gettoken; - } - KFW_AFS_error(rc, "ktc_GetToken()"); - code = rc; - goto cleanup; - } - - if (atoken.kvno == btoken.kvno && - atoken.ticketLen == btoken.ticketLen && - !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) && - !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen)) - { - goto cleanup; - } - - // * Reset the "aclient" structure before we call ktc_SetToken. - // * This structure was first set by the ktc_GetToken call when - // * we were comparing whether identical tokens already existed. - - strncpy(aclient.name, creds.pname, MAXKTCNAMELEN - 1); - if (creds.pinst[0]) - { - strncat(aclient.name, ".", MAXKTCNAMELEN - 1); - strncat(aclient.name, creds.pinst, MAXKTCNAMELEN - 1); - } - strcpy(aclient.instance, ""); - - if ( strcmp(realm_of_cell, creds.realm) ) - { - char * p; - strncat(aclient.name, "@", MAXKTCNAMELEN - 1); - strncpy(aclient.name, creds.realm, MAXKTCREALMLEN - 1); - } - aclient.name[MAXKTCREALMLEN-1] = '\0'; - - strcpy(aclient.cell, CellName); - - if (rc = pktc_SetToken(&aserver, &atoken, &aclient, 0)) - { - KFW_AFS_error(rc, "ktc_SetToken()"); - code = rc; - goto cleanup; - } - - cleanup: - if (cname) - pkrb5_free_unparsed_name(ctx,cname); - if (sname) - pkrb5_free_unparsed_name(ctx,sname); - if (client_principal) - pkrb5_free_principal(ctx,client_principal); - /* increds.client == client_principal */ - if (increds.server) - pkrb5_free_principal(ctx,increds.server); - if (cc && (cc != alt_cc)) - pkrb5_cc_close(ctx, cc); - if (ctx && (ctx != alt_ctx)) - pkrb5_free_context(ctx); - - return(rc? rc : code); -} - -/**************************************/ -/* afs_realm_of_cell(): */ -/**************************************/ -static char * -afs_realm_of_cell(afsconf_cell *cellconfig) -{ - static char krbrlm[REALM_SZ+1]=""; - krb5_context ctx = 0; - char ** realmlist=NULL; - krb5_error_code r; - - if (!cellconfig) - return 0; - - if (!pkrb5_init_context) - return 0; - - r = pkrb5_init_context(&ctx); - if ( !r ) - r = pkrb5_get_host_realm(ctx, cellconfig->hostName[0], &realmlist); - if ( !r && realmlist && realmlist[0] ) { - strcpy(krbrlm, realmlist[0]); - pkrb5_free_host_realm(ctx, realmlist); - } - if (ctx) - pkrb5_free_context(ctx); - - if ( !krbrlm[0] ) - { - char *s = krbrlm; - char *t = cellconfig->name; - int c; - - while (c = *t++) - { - if (islower(c)) c=toupper(c); - *s++ = c; - } - *s++ = 0; - } - return(krbrlm); -} - -/**************************************/ -/* get_cellconfig(): */ -/**************************************/ -static int -get_cellconfig(char *cell, afsconf_cell *cellconfig, char *local_cell) -{ - int rc; - char newcell[MAXCELLCHARS+1]; - - local_cell[0] = (char)0; - memset(cellconfig, 0, sizeof(*cellconfig)); - - /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */ - if (rc = pcm_GetRootCellName(local_cell)) - { - return(rc); - } - - if (strlen(cell) == 0) - strcpy(cell, local_cell); - - /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */ - strcpy(cellconfig->name, cell); - - return pcm_SearchCellFile(cell, newcell, get_cellconfig_callback, (void*)cellconfig); -} - -/**************************************/ -/* get_cellconfig_callback(): */ -/**************************************/ -static long -get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep) -{ - afsconf_cell *cc = (afsconf_cell *)cellconfig; - - cc->hostAddr[cc->numServers] = *addrp; - strcpy(cc->hostName[cc->numServers], namep); - cc->numServers++; - return(0); -} - - -/**************************************/ -/* KFW_AFS_error(): */ -/**************************************/ -void -KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName) -{ - char message[256]; - const char *errText; - - // Using AFS defines as error messages for now, until Transarc - // gets back to me with "string" translations of each of these - // const. defines. - if (rc == KTC_ERROR) - errText = "KTC_ERROR"; - else if (rc == KTC_TOOBIG) - errText = "KTC_TOOBIG"; - else if (rc == KTC_INVAL) - errText = "KTC_INVAL"; - else if (rc == KTC_NOENT) - errText = "KTC_NOENT"; - else if (rc == KTC_PIOCTLFAIL) - errText = "KTC_PIOCTLFAIL"; - else if (rc == KTC_NOPIOCTL) - errText = "KTC_NOPIOCTL"; - else if (rc == KTC_NOCELL) - errText = "KTC_NOCELL"; - else if (rc == KTC_NOCM) - errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!"; - else - errText = "Unknown error!"; - - sprintf(message, "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName); - - if ( IsDebuggerPresent() ) { - OutputDebugString(message); - OutputDebugString("\n"); - } - MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND); - return; -} - -static DWORD -GetServiceStatus( - LPSTR lpszMachineName, - LPSTR lpszServiceName, - DWORD *lpdwCurrentState) -{ - DWORD hr = NOERROR; - SC_HANDLE schSCManager = NULL; - SC_HANDLE schService = NULL; - DWORD fdwDesiredAccess = 0; - SERVICE_STATUS ssServiceStatus = {0}; - BOOL fRet = FALSE; - - *lpdwCurrentState = 0; - - fdwDesiredAccess = GENERIC_READ; - - schSCManager = OpenSCManager(lpszMachineName, - NULL, - fdwDesiredAccess); - - if(schSCManager == NULL) - { - hr = GetLastError(); - goto cleanup; - } - - schService = OpenService(schSCManager, - lpszServiceName, - fdwDesiredAccess); - - if(schService == NULL) - { - hr = GetLastError(); - goto cleanup; - } - - fRet = QueryServiceStatus(schService, - &ssServiceStatus); - - if(fRet == FALSE) - { - hr = GetLastError(); - goto cleanup; - } - - *lpdwCurrentState = ssServiceStatus.dwCurrentState; - -cleanup: - - CloseServiceHandle(schService); - CloseServiceHandle(schSCManager); - - return(hr); -} - -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, // [out, optional] - DLL handle - int* pindex, // [out, optional] - index of last func loaded (-1 if none) - int cleanup, // cleanup function pointers and unload on error - int go_on, // continue loading even if some functions cannot be loaded - int silent // do not pop-up a system dialog if DLL cannot be loaded - ) -{ - 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; -} - -#ifdef USE_FSPROBE -// Cell Accessibility Functions -// based on work originally submitted to the CMU Computer Club -// by Jeffrey Hutzelman -// -// These would work great if the fsProbe interface had been -// ported to Windows - -static -void probeComplete() -{ - fsprobe_Cleanup(1); - rx_Finalize(); -} - -struct ping_params { - unsigned short port; // in - int retry_delay; // in seconds - int verbose; // in - struct { - int wait; // in seconds - int retry; // in attempts - } host; - int max_hosts; // in - int hosts_attempted; // out -} - -// the fsHandler is where we receive the answer to the probe -static -int fsHandler(void) -{ - ping_count = fsprobe_Results.probeNum; - if (!*fsprobe_Results.probeOK) - { - ok_count++; - if (waiting) complete(); - } - if (ping_count == retry) - complete(); - return 0; -} - -// ping_fs is a callback routine meant to be called from within -// cm_SearchCellFile() or cm_SearchCellDNS() -static long -pingFS(void *ping_params, struct sockaddr_in *addrp, char *namep) -{ - int rc; - struct ping_params * pp = (struct ping_params *) ping_params; - - if ( pp->max_hosts && pp->hosts_attempted >= pp->max_hosts ) - return 0; - - pp->hosts_attempted++; - - if (pp->port && addrp->sin_port != htons(pp->port)) - addrp->sin_port = htons(pp->port); - - rc = fsprobe_Init(1, addrp, pp->retry_delay, fsHandler, pp->verbose); - if (rc) - { - fprintf(stderr, "fsprobe_Init failed (%d)\n", rc); - fsprobe_Cleanup(1); - return 0; - } - - for (;;) - { - tv.tv_sec = pp->host.wait; - tv.tv_usec = 0; - if (IOMGR_Select(0, 0, 0, 0, &tv)) - break; - } - probeComplete(); - return(0); -} - - -static BOOL -pingCell(char *cell) -{ - int rc; - char rootcell[MAXCELLCHARS+1]; - char newcell[MAXCELLCHARS+1]; - struct ping_params pp; - - memset(&pp, 0, sizeof(struct ping_params)); - - if (!cell || strlen(cell) == 0) { - /* WIN32 NOTE: no way to get max chars */ - if (rc = pcm_GetRootCellName(rootcell)) - return(FALSE); - cell = rootcell; - } - - pp.port = 7000; // AFS FileServer - pp.retry_delay = 10; - pp.max_hosts = 3; - pp.host.wait = 30; - pp.host.retry = 0; - pp.verbose = 1; - - /* WIN32: cm_SearchCellFile(cell, pcallback, pdata) */ - rc = pcm_SearchCellFile(cell, newcell, pingFS, (void *)&pp); -} -#endif /* USE_FSPROBE */ - -// These two items are imported from afscreds.h -// but it cannot be included without causing conflicts -#define c100ns1SECOND (LONGLONG)10000000 -static void -TimeToSystemTime (SYSTEMTIME *pst, time_t TimeT) -{ - struct tm *pTime; - memset (pst, 0x00, sizeof(SYSTEMTIME)); - - if ((pTime = localtime (&TimeT)) != NULL) - { - pst->wYear = pTime->tm_year + 1900; - pst->wMonth = pTime->tm_mon + 1; - pst->wDayOfWeek = pTime->tm_wday; - pst->wDay = pTime->tm_mday; - pst->wHour = pTime->tm_hour; - pst->wMinute = pTime->tm_min; - pst->wSecond = pTime->tm_sec; - pst->wMilliseconds = 0; - } -} - -void -ObtainTokensFromUserIfNeeded(HWND hWnd) -{ - char * rootcell = NULL; - char cell[MAXCELLCHARS+1] = ""; - char password[PROBE_PASSWORD_LEN+1]; - krb5_data pwdata; - afsconf_cell cellconfig; - struct ktc_principal aserver; - struct ktc_principal aclient; - struct ktc_token atoken; - krb5_context ctx = 0; - krb5_timestamp now = 0; - krb5_error_code code; - int serverReachable = 0; - int rc; -#ifndef USE_FSPROBE - krb5_ccache cc = 0; - const char * realm = 0; - krb5_principal principal = 0; - char * pname = 0; -#endif /* USE_FSPROBE */ - DWORD CurrentState; - char HostName[64]; - int use_kfw = KFW_is_available(); - - CurrentState = 0; - memset(HostName, '\0', sizeof(HostName)); - gethostname(HostName, sizeof(HostName)); - if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) - return; - if (CurrentState != SERVICE_RUNNING) { - SendMessage(hWnd, WM_START_SERVICE, FALSE, 0L); - return; - } - - if (!pkrb5_init_context) - return; - - if ( use_kfw ) { - code = pkrb5_init_context(&ctx); - if ( code ) goto cleanup; - } - - rootcell = (char *)GlobalAlloc(GPTR,MAXCELLCHARS+1); - if ( !rootcell ) goto cleanup; - - code = get_cellconfig(cell, (void*)&cellconfig, rootcell); - if ( code ) goto cleanup; - - memset(&aserver, '\0', sizeof(aserver)); - strcpy(aserver.name, "afs"); - strcpy(aserver.cell, rootcell); - - rc = pktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient); - - if ( use_kfw ) { - code = pkrb5_timeofday(ctx, &now); - if ( code ) - now = 0; - - if (!rc && (now < atoken.endTime)) - goto cleanup; - - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"KFW_AFS_klog() returns: %d now = %ul endTime = %ul\n", - rc, now, atoken.endTime); - OutputDebugString(message); - } - } else { - SYSTEMTIME stNow; - FILETIME ftNow; - FILETIME ftExpires; - LONGLONG llNow; - LONGLONG llExpires; - SYSTEMTIME stExpires; - - TimeToSystemTime (&stExpires, atoken.endTime); - GetLocalTime (&stNow); - SystemTimeToFileTime (&stNow, &ftNow); - SystemTimeToFileTime (&stExpires, &ftExpires); - - llNow = (((LONGLONG)ftNow.dwHighDateTime) << 32) + (LONGLONG)(ftNow.dwLowDateTime); - llExpires = (((LONGLONG)ftExpires.dwHighDateTime) << 32) + (LONGLONG)(ftExpires.dwLowDateTime); - - llNow /= c100ns1SECOND; - llExpires /= c100ns1SECOND; - - if (!rc && (llNow < llExpires)) - goto cleanup; - - if ( IsDebuggerPresent() ) { - char message[256]; - sprintf(message,"KFW_AFS_klog() returns: %d now = %ul endTime = %ul\n", - rc, llNow, llExpires); - OutputDebugString(message); - } - } - - -#ifdef USE_FSPROBE - serverReachable = cellPing(NULL); -#else - if ( use_kfw ) { - // If we can't use the FSProbe interface we can attempt to forge - // a kinit and if we can back an invalid user error we know the - // kdc is at least reachable - realm = afs_realm_of_cell(&cellconfig); // do not free - - code = pkrb5_build_principal(ctx, &principal, strlen(realm), - realm, PROBE_USERNAME, NULL, NULL); - if ( code ) goto cleanup; - - code = KFW_get_ccache(ctx, principal, &cc); - if ( code ) goto cleanup; - - code = pkrb5_unparse_name(ctx, principal, &pname); - if ( code ) goto cleanup; - - pwdata.data = password; - pwdata.length = PROBE_PASSWORD_LEN; - code = pkrb5_c_random_make_octets(ctx, &pwdata); - if (code) { - int i; - for ( i=0 ; i - -DWORD -GetNumOfIpAddrs(void) -{ - PMIB_IPADDRTABLE pIpAddrTable = NULL; - ULONG dwSize; - DWORD code; - DWORD index; - DWORD validAddrs = 0; - - dwSize = 0; - code = GetIpAddrTable(NULL, &dwSize, 0); - if (code == ERROR_INSUFFICIENT_BUFFER) { - pIpAddrTable = malloc(dwSize); - code = GetIpAddrTable(pIpAddrTable, &dwSize, 0); - if ( code == NO_ERROR ) { - for ( index=0; index < pIpAddrTable->dwNumEntries; index++ ) { - if (pIpAddrTable->table[index].dwAddr != 0) - validAddrs++; - } - } - free(pIpAddrTable); - } - return validAddrs; -} - -void -IpAddrChangeMonitor(void * hWnd) -{ -#ifdef USE_OVERLAPPED - HANDLE Handle = INVALID_HANDLE_VALUE; /* Do Not Close This Handle */ - OVERLAPPED Ovlap; -#endif /* USE_OVERLAPPED */ - DWORD Result; - DWORD prevNumOfAddrs = GetNumOfIpAddrs(); - DWORD NumOfAddrs; - char message[256]; - - if ( !hWnd ) - return; - - while ( TRUE ) { -#ifdef USE_OVERLAPPED - ZeroMemory(&Ovlap, sizeof(OVERLAPPED)); - - Result = NotifyAddrChange(&Handle,&Ovlap); - if (Result != ERROR_IO_PENDING) - { - if ( IsDebuggerPresent() ) { - sprintf(message, "NotifyAddrChange() failed with error %d \n", Result); - OutputDebugString(message); - } - break; - } - - if ((Result = WaitForSingleObject(Handle,INFINITE)) != WAIT_OBJECT_0) - { - if ( IsDebuggerPresent() ) { - sprintf(message, "WaitForSingleObject() failed with error %d\n", - GetLastError()); - OutputDebugString(message); - } - continue; - } - - if (GetOverlappedResult(Handle, &Ovlap, - &DataTransfered, TRUE) == 0) - { - if ( IsDebuggerPresent() ) { - sprintf(message, "GetOverlapped result failed %d \n", - GetLastError()); - OutputDebugString(message); - } - break; - } -#else - Result = NotifyAddrChange(NULL,NULL); - if (Result != NO_ERROR) - { - if ( IsDebuggerPresent() ) { - sprintf(message, "NotifyAddrChange() failed with error %d \n", Result); - OutputDebugString(message); - } - break; - } -#endif - - NumOfAddrs = GetNumOfIpAddrs(); - - if ( IsDebuggerPresent() ) { - sprintf(message,"IPAddrChangeMonitor() NumOfAddrs: now %d was %d\n", - NumOfAddrs, prevNumOfAddrs); - OutputDebugString(message); - } - - if ( NumOfAddrs != prevNumOfAddrs ) { - // Give AFS Client Service a chance to notice and die - // Or for network services to startup - Sleep(2000); - // this call should probably be mutex protected - ObtainTokensFromUserIfNeeded(hWnd); - } - prevNumOfAddrs = NumOfAddrs; - } -} - - -DWORD -IpAddrChangeMonitorInit(HWND hWnd) -{ - DWORD status = ERROR_SUCCESS; - HANDLE thread; - ULONG threadID = 0; - - thread = CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)IpAddrChangeMonitor, - hWnd, 0, &threadID); - - if (thread == NULL) { - status = GetLastError(); - } - CloseHandle(thread); - return status; -} - diff --git a/src/WINNT/client_creds/afskfw.h b/src/WINNT/client_creds/afskfw.h deleted file mode 100644 index a34341b47..000000000 --- a/src/WINNT/client_creds/afskfw.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2003 SkyRope, LLC - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - Neither the name of Skyrope, LLC nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission from Skyrope, LLC. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef AFSKFW_H -#define AFSKFW_H -#ifdef __cplusplus -extern "C" { -#endif -void KFW_initialize(void); -void KFW_cleanup(void); -int KFW_is_available(void); -int KFW_AFS_destroy_tickets_for_cell(char *); -int KFW_AFS_renew_expiring_tokens(void); -int KFW_AFS_get_cred( char * username, - char * instance, - char * cell, - char * password, - int lifetime, - char ** reasonP ); -int KFW_AFS_renew_token_for_cell(char * cell); -int KFW_AFS_renew_tokens_for_all_cells(void); -BOOL KFW_AFS_wait_for_service_start(void); - -#define WM_OBTAIN_TOKENS (WM_USER+77) -#define WM_START_SERVICE (WM_USER+78) -void ObtainTokensFromUserIfNeeded(HWND hWnd); -DWORD IpAddrChangeMonitorInit(HWND hWnd); - -#ifdef __cplusplus -} -#endif -#endif /* AFSKFW_H */ diff --git a/src/WINNT/client_creds/creds.cpp b/src/WINNT/client_creds/creds.cpp index 930418c79..7cf0c594c 100644 --- a/src/WINNT/client_creds/creds.cpp +++ b/src/WINNT/client_creds/creds.cpp @@ -7,17 +7,19 @@ * directory or online at http://www.openafs.org/dl/license10.html */ -#include "afscreds.h" -#include "afskfw.h" - extern "C" { #include #include #include #include +#include #include +#include +#include "ipaddrchg.h" } +#include "afscreds.h" + /* * DEFINITIONS ________________________________________________________________ @@ -390,11 +392,17 @@ int ObtainNewCredentials (LPCTSTR pszCell, LPCTSTR pszUser, LPCTSTR pszPassword, char szPasswordA[ 256 ]; CopyStringToAnsi (szPasswordA, pszPassword); + char szSmbNameA[ MAXRANDOMNAMELEN ]; + CopyStringToAnsi (szSmbNameA, g.SmbName); + int Expiration = 0; if ( KFW_is_available() ) - rc = KFW_AFS_get_cred(szNameA, NULL, szCellA, szPasswordA, 0, &Result); - else + rc = KFW_AFS_get_cred(szNameA, NULL, szCellA, szPasswordA, 0, szSmbNameA[0] ? szSmbNameA : NULL, &Result); + else if ( szSmbNameA[0] ) + rc = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON, + szNameA, "", szCellA, szPasswordA, szSmbNameA, 0, &Expiration, 0, &Result); + else rc = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, szNameA, "", szCellA, szPasswordA, 0, &Expiration, 0, &Result); } diff --git a/src/WINNT/client_creds/main.cpp b/src/WINNT/client_creds/main.cpp index 6a977c567..ce24a9bf9 100644 --- a/src/WINNT/client_creds/main.cpp +++ b/src/WINNT/client_creds/main.cpp @@ -12,6 +12,9 @@ extern "C" { #include #include #include +#include +#include +#include "ipaddrchg.h" } #include "afscreds.h" @@ -19,8 +22,6 @@ extern "C" { #include "drivemap.h" #include #include -#include "rxkad.h" -#include "afskfw.h" /* * DEFINITIONS ________________________________________________________________ @@ -93,6 +94,11 @@ BOOL InitApp (LPSTR pszCmdLineA) BOOL fNetDetect = FALSE; BOOL fRenewMaps = FALSE; + // Initialize our global variables and window classes + // + memset (&g, 0x00, sizeof(g)); + g.fStartup = TRUE; + // Parse the command-line // while (pszCmdLineA && *pszCmdLineA) @@ -143,6 +149,7 @@ BOOL InitApp (LPSTR pszCmdLineA) break; case ':': + CopyAnsiToString(g.SmbName,pszCmdLineA); MapShareName(pszCmdLineA); break; @@ -205,11 +212,6 @@ BOOL InitApp (LPSTR pszCmdLineA) if (fExit || fUninstall || fInstall) return FALSE; - // Initialize our global variables and window classes - // - memset (&g, 0x00, sizeof(g)); - g.fStartup = TRUE; - HKEY hk; if (RegOpenKey (HKEY_CURRENT_USER, REGSTR_PATH_OPENAFS_CLIENT, &hk) == 0) { diff --git a/src/WINNT/client_creds/window.cpp b/src/WINNT/client_creds/window.cpp index e80b0b3ea..73ae6daaf 100644 --- a/src/WINNT/client_creds/window.cpp +++ b/src/WINNT/client_creds/window.cpp @@ -10,11 +10,11 @@ extern "C" { #include #include +#include +#include "ipaddrchg.h" } #include "afscreds.h" -#include "afskfw.h" - /* * DEFINITIONS ________________________________________________________________