2 * Copyright (c) 2004, 2005, 2006, 2007, 2008 Secure Endpoints Inc.
3 * Copyright (c) 2003 SkyRope, LLC
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * - Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * - Neither the name of Skyrope, LLC nor the names of its contributors may be
15 * used to endorse or promote products derived from this software without
16 * specific prior written permission from Skyrope, LLC.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * Portions of this code are derived from portions of the MIT
31 * Leash Ticket Manager and LoadFuncs utilities. For these portions the
32 * following copyright applies.
34 * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology.
35 * All rights reserved.
37 * Export of this software from the United States of America may
38 * require a specific license from the United States Government.
39 * It is the responsibility of any person or organization contemplating
40 * export to obtain such a license before exporting.
42 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
43 * distribute this software and its documentation for any purpose and
44 * without fee is hereby granted, provided that the above copyright
45 * notice appear in all copies and that both that copyright notice and
46 * this permission notice appear in supporting documentation, and that
47 * the name of M.I.T. not be used in advertising or publicity pertaining
48 * to distribution of the software without specific, written prior
49 * permission. Furthermore if you modify this software you must label
50 * your software as modified software and not distribute it in such a
51 * fashion that it might be confused with the original M.I.T. software.
52 * M.I.T. makes no representations about the suitability of
53 * this software for any purpose. It is provided "as is" without express
54 * or implied warranty.
62 #include <afsconfig.h>
63 #include <afs/param.h>
68 #include <afs/ptserver.h>
69 #include <afs/ptuser.h>
71 #include <afs/com_err.h>
73 #include <WINNT\afsreg.h>
77 #include "afskfw-int.h"
84 #include <krbcompat_delayload.h>
86 #ifndef KRB5_TC_OPENCLOSE
87 #define KRB5_TC_OPENCLOSE 0x00000001
91 * TIMING _____________________________________________________________________
95 #define cminREMIND_TEST 1 // test every minute for expired creds
96 #define cminREMIND_WARN 15 // warn if creds expire in 15 minutes
97 #define cminRENEW 20 // renew creds when there are 20 minutes remaining
98 #define cminMINLIFE 30 // minimum life of Kerberos creds
100 #define c100ns1SECOND (LONGLONG)10000000
101 #define cmsec1SECOND 1000
102 #define cmsec1MINUTE 60000
103 #define csec1MINUTE 60
105 /* Static Prototypes */
106 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
107 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *, unsigned short);
108 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
109 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
110 void *data, const char *name, const char *banner, int num_prompts,
111 krb5_prompt prompts[]);
113 /* Static Declarations */
114 static int inited = 0;
115 static int mid_cnt = 0;
116 static struct textField * mid_tb = NULL;
117 static struct principal_ccache_data * princ_cc_data = NULL;
118 static struct cell_principal_map * cell_princ_map = NULL;
121 #define DEFAULT_LIFETIME pLeash_get_default_lifetime()
123 #define DEFAULT_LIFETIME (24 * 60)
127 DebugPrintf(const char * fmt, ...)
129 if (IsDebuggerPresent()) {
134 StringCbVPrintfA(buf, sizeof(buf), fmt, vl);
135 OutputDebugStringA(buf);
143 static int inited = 0;
146 char mutexName[MAX_PATH];
147 HANDLE hMutex = NULL;
149 StringCbPrintf( mutexName, sizeof(mutexName), "AFS KFW Init pid=%d", getpid());
151 hMutex = CreateMutex( NULL, TRUE, mutexName );
152 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
153 if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
162 if ( KFW_is_available() ) {
163 char rootcell[CELL_MAXNAMELEN+1];
165 KFW_enable_DES(NULL);
167 KFW_import_windows_lsa();
168 #endif /* USE_MS2MIT */
169 KFW_import_ccache_data();
170 KFW_AFS_renew_expiring_tokens();
172 /* WIN32 NOTE: no way to get max chars */
173 if (!cm_GetRootCellName(rootcell))
174 KFW_AFS_renew_token_for_cell(rootcell);
177 ReleaseMutex(hMutex);
180 initialize_KTC_error_table();
181 initialize_PT_error_table();
190 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
193 static int init = TRUE;
194 static int bIsWow64 = FALSE;
198 LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
200 hModule = GetModuleHandle(TEXT("kernel32"));
202 fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process");
204 if (NULL != fnIsWow64Process)
206 if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
208 // on error, assume FALSE.
209 // in other words, do nothing.
212 FreeLibrary(hModule);
220 KFW_accept_dotted_usernames(void)
226 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
227 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
228 if (code == ERROR_SUCCESS) {
230 code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
231 (BYTE *) &value, &len);
232 RegCloseKey(parmKey);
234 if (code != ERROR_SUCCESS) {
235 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
236 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
237 if (code == ERROR_SUCCESS) {
239 code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
240 (BYTE *) &value, &len);
241 RegCloseKey (parmKey);
255 KFW_is_available(void)
261 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
262 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
263 if (code == ERROR_SUCCESS) {
264 len = sizeof(enableKFW);
265 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
266 (BYTE *) &enableKFW, &len);
267 RegCloseKey (parmKey);
270 if (code != ERROR_SUCCESS) {
271 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
272 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
273 if (code == ERROR_SUCCESS) {
274 len = sizeof(enableKFW);
275 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
276 (BYTE *) &enableKFW, &len);
277 RegCloseKey (parmKey);
286 /* If this is non-zero, then some Kerberos library was loaded. */
287 return (krb5_init_context != NULL);
291 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
292 int FreeContextFlag, krb5_context * context,
297 int krb5Error = ((int)(rc & 255));
299 errText = krb5_get_error_message(*context, rc);
300 StringCbPrintf(message, sizeof(message),
301 "%s\n(Kerberos error %ld)\n\n%s failed",
305 krb5_free_error_message(*context, (char *)errText);
307 DebugPrintf("%s", message);
309 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
313 if (FreeContextFlag == 1) {
315 if (context && *context != NULL) {
317 if (cache && *cache != NULL) {
318 krb5_cc_close(*context, *cache);
322 krb5_free_context(*context);
331 KFW_AFS_update_princ_ccache_data(krb5_context context, krb5_ccache cc, int lsa)
333 struct principal_ccache_data * next = princ_cc_data;
334 krb5_principal principal = 0;
336 const char * ccname = NULL;
337 const char * cctype = NULL;
338 char * ccfullname = NULL;
339 krb5_error_code code = 0;
340 krb5_error_code cc_code = 0;
347 if (context == 0 || cc == 0)
350 code = krb5_cc_get_principal(context, cc, &principal);
353 code = krb5_unparse_name(context, principal, &pname);
354 if ( code ) goto cleanup;
356 ccname = krb5_cc_get_name(context, cc);
357 if (!ccname) goto cleanup;
359 cctype = krb5_cc_get_type(context, cc);
360 if (!cctype) goto cleanup;
362 len = strlen(ccname) + strlen(cctype) + 2;
363 ccfullname = malloc(len);
364 if (!ccfullname) goto cleanup;
366 StringCbPrintf(ccfullname, len, "%s:%s", cctype, ccname);
368 // Search the existing list to see if we have a match
370 for ( ; next ; next = next->next ) {
371 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccfullname) )
376 // If not, match add a new node to the beginning of the list and assign init it
378 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
379 next->next = princ_cc_data;
380 princ_cc_data = next;
381 next->principal = strdup(pname);
382 next->ccache_name = ccfullname;
384 next->from_lsa = lsa;
386 next->expiration_time = 0;
390 flags = 0; // turn off OPENCLOSE mode
391 code = krb5_cc_set_flags(context, cc, flags);
392 if ( code ) goto cleanup;
394 code = krb5_timeofday(context, &now);
396 cc_code = krb5_cc_start_seq_get(context, cc, &cur);
398 while (!(cc_code = krb5_cc_next_cred(context, cc, &cur, &creds))) {
399 if ( creds.flags.b.initial) {
401 // we found the ticket we are looking for
402 // check validity of timestamp
403 // We add a 5 minutes fudge factor to compensate for potential
404 // clock skew errors between the KDC and client OS
406 valid = ((creds.times.starttime > 0) &&
407 now >= (creds.times.starttime - 300) &&
408 now < (creds.times.endtime + 300) &&
409 !creds.flags.b.invalid);
411 if ( next->from_lsa) {
413 next->expiration_time = creds.times.endtime;
415 } else if ( valid ) {
417 next->expiration_time = creds.times.endtime;
418 next->renew = (creds.times.renew_till > creds.times.endtime) &&
419 creds.flags.b.renewable;
422 next->expiration_time = 0;
426 krb5_free_cred_contents(context, &creds);
427 cc_code = KRB5_CC_END;
430 krb5_free_cred_contents(context, &creds);
433 if (cc_code == KRB5_CC_END) {
434 code = krb5_cc_end_seq_get(context, cc, &cur);
435 if (code) goto cleanup;
439 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
440 code = krb5_cc_set_flags(context, cc, flags);
445 krb5_free_unparsed_name(context,pname);
447 krb5_free_principal(context,principal);
451 KFW_AFS_find_ccache_for_principal(krb5_context context, char * principal,
452 char **ccache, int valid_only)
454 struct principal_ccache_data * next = princ_cc_data;
455 char * response = NULL;
457 if ( !principal || !ccache )
461 if ( (!valid_only || !next->expired) && !strcmp(next->principal, principal) ) {
463 // we always want to prefer the MS Kerberos LSA cache or
464 // the cache afscreds created specifically for the principal
465 // if the current entry is either one, drop the previous find
466 if ( next->from_lsa || !strcmp(next->ccache_name, principal) )
469 response = strdup(next->ccache_name);
470 // MS Kerberos LSA is our best option so use it and quit
471 if ( next->from_lsa )
485 KFW_AFS_delete_princ_ccache_data(krb5_context context, char * pname, char * ccname)
487 struct principal_ccache_data ** next = &princ_cc_data;
489 if ( !pname && !ccname )
493 if ( !strcmp((*next)->principal,pname) ||
494 !strcmp((*next)->ccache_name,ccname) ) {
496 free((*next)->principal);
497 free((*next)->ccache_name);
499 (*next) = (*next)->next;
506 KFW_AFS_update_cell_princ_map(krb5_context context, char * cell, char *pname, int active)
508 struct cell_principal_map * next = cell_princ_map;
510 // Search the existing list to see if we have a match
512 for ( ; next ; next = next->next ) {
513 if ( !strcmp(next->cell, cell) ) {
514 if ( !strcmp(next->principal,pname) ) {
515 next->active = active;
518 // OpenAFS currently has a restriction of one active token per cell
519 // Therefore, whenever we update the table with a new active cell we
520 // must mark all of the other principal to cell entries as inactive.
528 // If not, match add a new node to the beginning of the list and assign init it
530 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
531 next->next = cell_princ_map;
532 cell_princ_map = next;
533 next->principal = strdup(pname);
534 next->cell = strdup(cell);
535 next->active = active;
540 KFW_AFS_delete_cell_princ_maps(krb5_context context, char * pname, char * cell)
542 struct cell_principal_map ** next = &cell_princ_map;
544 if ( !pname && !cell )
548 if ( !strcmp((*next)->principal,pname) ||
549 !strcmp((*next)->cell,cell) ) {
551 free((*next)->principal);
554 (*next) = (*next)->next;
560 // Returns (if possible) a principal which has been known in
561 // the past to have been used to obtain tokens for the specified
563 // TODO: Attempt to return one which has not yet expired by checking
564 // the principal/ccache data
566 KFW_AFS_find_principals_for_cell(krb5_context context, char * cell, char **principals[], int active_only)
568 struct cell_principal_map * next_map = cell_princ_map;
569 const char * princ = NULL;
576 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
579 next_map = next_map->next;
582 if ( !principals || !count )
585 *principals = (char **) malloc(sizeof(char *) * count);
586 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
588 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
589 (*principals)[i++] = strdup(next_map->principal);
596 KFW_AFS_find_cells_for_princ(krb5_context context, char * pname, char **cells[], int active_only)
599 struct cell_principal_map * next_map = cell_princ_map;
600 const char * princ = NULL;
606 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
609 next_map = next_map->next;
615 *cells = (char **) malloc(sizeof(char *) * count);
616 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
618 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
619 (*cells)[i++] = strdup(next_map->cell);
626 escape_unsafe_principal_characters(const char * pname,
634 for (src = pname; *src != '\0'; ++len, ++src) {
635 if (*src == '\\' || *src == '#' || *src == '<' ||
636 *src == '>' || *src == ':' || *src == '"' ||
637 *src == '/' || *src == '|' || *src == '?' ||
644 *new_name = (char *) malloc(len);
646 if (*new_name == NULL)
649 for (src = pname, dest = *new_name; *src != '\0'; ++src) {
651 case '\\': *dest++ = '#'; *dest++ = 'b'; break;
653 case '#' : *dest++ = '#'; *dest++ = '#'; break;
655 case '<' : *dest++ = '#'; *dest++ = 'l'; break;
657 case '>' : *dest++ = '#'; *dest++ = 'g'; break;
659 case ':' : *dest++ = '#'; *dest++ = 'c'; break;
661 case '"' : *dest++ = '#'; *dest++ = 't'; break;
663 case '/' : *dest++ = '#'; *dest++ = 'f'; break;
665 case '|' : *dest++ = '#'; *dest++ = 'p'; break;
667 case '?' : *dest++ = '#'; *dest++ = 'q'; break;
669 case '*' : *dest++ = '#'; *dest++ = 'a'; break;
671 default: *dest++ = *src;
679 get_default_ccache_name_for_principal(krb5_context context, krb5_principal principal,
683 krb5_error_code code;
688 code = krb5_unparse_name(context, principal, &pname);
689 if (code) goto cleanup;
691 len = strlen(pname) + 5;
692 *cc_name = (char *) malloc(len);
694 StringCbPrintfA(*cc_name, len, "API:%s", pname, GetCurrentThreadId());
698 krb5_free_unparsed_name(context, pname);
704 is_default_ccache_for_principal(krb5_context context, krb5_principal principal,
707 const char * cc_name;
708 char * def_cc_name = NULL;
710 const char *bs_def_cc;
713 cc_name = krb5_cc_get_name(context, cc);
715 get_default_ccache_name_for_principal(context, principal, &def_cc_name);
717 is_default = (cc_name != NULL && def_cc_name != NULL &&
719 (bs_cc = strrchr(cc_name, '\\')) != NULL &&
721 (bs_def_cc = strrchr(def_cc_name, '\\')) != NULL &&
723 !strcmp(bs_cc, bs_def_cc));
731 /** Given a principal return an existing ccache or create one and return */
733 KFW_get_ccache(krb5_context alt_context, krb5_principal principal, krb5_ccache * cc)
735 krb5_context context = NULL;
737 char * ccname = NULL;
738 krb5_error_code code;
741 context = alt_context;
743 code = krb5_init_context(&context);
744 if (code) goto cleanup;
748 code = krb5_unparse_name(context, principal, &pname);
749 if (code) goto cleanup;
751 if ( !KFW_AFS_find_ccache_for_principal(context,pname,&ccname,TRUE) &&
752 !KFW_AFS_find_ccache_for_principal(context,pname,&ccname,FALSE)) {
754 get_default_ccache_name_for_principal(context, principal, &ccname);
756 code = krb5_cc_resolve(context, ccname, cc);
758 code = krb5_cc_default(context, cc);
759 if (code) goto cleanup;
766 krb5_free_unparsed_name(context,pname);
767 if (context && (context != alt_context))
768 krb5_free_context(context);
774 // Import Microsoft Credentials into a new MIT ccache
776 KFW_import_windows_lsa(void)
778 krb5_context context = NULL;
779 krb5_ccache cc = NULL;
780 krb5_principal princ = NULL;
782 const char * princ_realm;
783 krb5_error_code code;
784 char cell[128]="", realm[128]="", *def_realm = 0;
785 DWORD dwMsLsaImport = 1;
787 code = krb5_init_context(&context);
788 if (code) goto cleanup;
790 code = krb5_cc_resolve(context, LSA_CCNAME, &cc);
791 if (code) goto cleanup;
793 KFW_AFS_update_princ_ccache_data(context, cc, TRUE);
795 code = krb5_cc_get_principal(context, cc, &princ);
796 if ( code ) goto cleanup;
798 dwMsLsaImport = KFW_get_default_mslsa_import(context);
799 switch ( dwMsLsaImport ) {
800 case 0: /* do not import */
802 case 1: /* always import */
804 case 2: { /* matching realm */
805 const char *ms_realm;
807 ms_realm = krb5_principal_get_realm(context, princ);
809 if (code = krb5_get_default_realm(context, &def_realm))
812 if (strcmp(def_realm, ms_realm))
820 code = krb5_unparse_name(context,princ,&pname);
821 if ( code ) goto cleanup;
823 princ_realm = krb5_principal_get_realm(context, princ);
824 StringCchCopyA(realm, sizeof(realm), princ_realm);
825 StringCchCopyA(cell, sizeof(cell), princ_realm);
828 code = KFW_AFS_klog(context, cc, "afs", cell, realm,
829 KFW_get_default_lifetime(context, realm), NULL);
831 DebugPrintf("KFW_AFS_klog() returns: %d\n", code);
833 if ( code ) goto cleanup;
835 KFW_AFS_update_cell_princ_map(context, cell, pname, TRUE);
839 krb5_free_unparsed_name(context,pname);
841 krb5_free_principal(context,princ);
843 krb5_free_default_realm(context, def_realm);
845 krb5_cc_close(context,cc);
847 krb5_free_context(context);
849 #endif /* USE_MS2MIT */
852 get_canonical_ccache(krb5_context context, krb5_ccache * pcc)
854 krb5_error_code code;
855 krb5_ccache cc = *pcc;
856 krb5_principal principal = 0;
858 code = krb5_cc_get_principal(context, cc, &principal);
862 if ( !is_default_ccache_for_principal(context, principal, cc)
863 && strcmp(krb5_cc_get_type(context, cc), LSA_CCTYPE) != 0) {
865 char * def_cc_name = NULL;
866 krb5_ccache def_cc = 0;
867 krb5_principal def_cc_princ = 0;
870 get_default_ccache_name_for_principal(context, principal, &def_cc_name);
872 code = krb5_cc_resolve(context, def_cc_name, &def_cc);
875 code = krb5_cc_get_principal(context, def_cc, &def_cc_princ);
876 if (code || !krb5_principal_compare(context, def_cc_princ, principal)) {
877 /* def_cc either doesn't exist or is home to an
880 DebugPrintf("Copying ccache [%s:%s]->[%s:%s]",
881 krb5_cc_get_type(context, cc), krb5_cc_get_name(context, cc),
882 krb5_cc_get_type(context, def_cc),
883 krb5_cc_get_name(context, def_cc));
885 code = krb5_cc_initialize(context, def_cc, principal);
888 code = krb5_cc_copy_creds(context, cc, def_cc);
890 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
894 code = krb5_cc_close(context, cc);
902 krb5_cc_close(context, def_cc);
905 krb5_free_principal(context, def_cc_princ);
912 krb5_free_principal(context, principal);
914 if (code == 0 && cc != 0) {
923 static krb5_error_code
924 check_and_get_tokens_for_ccache(krb5_context context, krb5_ccache cc)
926 krb5_error_code code = 0;
927 krb5_error_code cc_code = 0;
930 char * principal_name = NULL;
933 krb5_principal principal = 0;
934 code = krb5_cc_get_principal(context, cc, &principal);
937 code = krb5_unparse_name(context, principal, &principal_name);
940 krb5_free_principal(context, principal);
945 krb5_free_unparsed_name(context, principal_name);
949 cc_code = krb5_cc_start_seq_get(context, cc, &cur);
951 while (!(cc_code = krb5_cc_next_cred(context, cc, &cur, &creds))) {
953 const char * sname = krb5_principal_get_comp_string(context, creds.server, 0);
954 const char * cell = krb5_principal_get_comp_string(context, creds.server, 1);
955 const char * realm = krb5_principal_get_realm(context, creds.server);
957 if ( sname && cell && !strcmp("afs",sname) ) {
959 struct ktc_principal aserver;
960 struct ktc_principal aclient;
961 struct ktc_token atoken;
964 DebugPrintf("Found AFS ticket: %s%s%s@%s\n",
965 sname, (cell ? "/":""), (cell? cell : ""), realm);
967 memset(&aserver, '\0', sizeof(aserver));
968 StringCbCopy(aserver.name, sizeof(aserver.name), sname);
969 StringCbCopy(aserver.cell, sizeof(aserver.cell), cell);
971 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
973 // Found a token in AFS Client Server which matches
975 char pname[128], *p, *q;
977 for ( p=pname, q=aclient.name; *q; p++, q++)
980 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
985 DebugPrintf("Found AFS token: %s\n", pname);
987 if (strcmp(pname, principal_name) != 0)
990 KFW_AFS_update_cell_princ_map(context, cell, principal_name, active);
993 // Attempt to import it
995 KFW_AFS_update_cell_princ_map(context, cell, principal_name, active);
997 DebugPrintf("Calling KFW_AFS_klog() to obtain token\n");
999 code = KFW_AFS_klog(context, cc, "afs", cell, realm,
1000 KFW_get_default_lifetime(context, realm), NULL);
1002 DebugPrintf("KFW_AFS_klog() returns: %d\n", code);
1007 DebugPrintf("Found ticket: %s%s%s@%s\n", sname,
1008 (cell? "/":""), (cell? cell:""), realm);
1011 krb5_free_cred_contents(context, &creds);
1014 if (cc_code == KRB5_CC_END) {
1015 cc_code = krb5_cc_end_seq_get(context, cc, &cur);
1021 // If there are existing MIT credentials, copy them to a new
1022 // ccache named after the principal
1024 // Enumerate all existing MIT ccaches and construct entries
1025 // in the principal_ccache table
1027 // Enumerate all existing AFS Tokens and construct entries
1028 // in the cell_principal table
1030 KFW_import_ccache_data(void)
1032 krb5_context context = NULL;
1034 krb5_error_code code;
1035 krb5_cccol_cursor cccol_cur;
1038 if ( IsDebuggerPresent() )
1039 OutputDebugString("KFW_import_ccache_data()\n");
1041 code = krb5_init_context(&context);
1042 if (code) goto cleanup;
1044 code = krb5_cccol_cursor_new(context, &cccol_cur);
1045 if (code) goto cleanup;
1047 while ((code = krb5_cccol_cursor_next(context, cccol_cur, &cc)) == 0 && cc != NULL) {
1049 if (!get_canonical_ccache(context, &cc)) {
1051 krb5_cc_close(context, cc);
1055 /* Turn off OPENCLOSE mode */
1056 code = krb5_cc_set_flags(context, cc, 0);
1057 if ( code ) goto cleanup;
1059 KFW_AFS_update_princ_ccache_data(context, cc,
1060 !strcmp(krb5_cc_get_type(context, cc),
1063 check_and_get_tokens_for_ccache(context, cc);
1065 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1066 code = krb5_cc_set_flags(context, cc, flags);
1069 krb5_cc_close(context,cc);
1074 krb5_cccol_cursor_free(context, &cccol_cur);
1078 krb5_free_context(context);
1082 KFW_enable_DES(krb5_context alt_context)
1084 krb5_context context;
1085 krb5_error_code code;
1087 if ( alt_context ) {
1088 context = alt_context;
1090 code = krb5_init_context(&context);
1091 if (code) goto cleanup;
1094 if (krb5_enctype_valid(context, ETYPE_DES_CBC_CRC))
1095 krb5_enctype_enable(context, ETYPE_DES_CBC_CRC);
1098 if (context && (context != alt_context))
1099 krb5_free_context(context);
1104 KFW_AFS_get_cred( char * username,
1111 static char reason[1024]="";
1112 krb5_context context = NULL;
1113 krb5_ccache cc = NULL;
1114 char * realm = NULL, * userrealm = NULL;
1115 krb5_principal principal = NULL;
1116 char * pname = NULL;
1117 krb5_error_code code;
1118 char local_cell[CELL_MAXNAMELEN+1];
1119 char **cells = NULL;
1121 struct afsconf_cell cellconfig;
1124 DebugPrintf("KFW_AFS_get_cred for token %s in cell %s\n", username, cell);
1126 memset(&cellconfig, 0, sizeof(cellconfig));
1128 code = krb5_init_context(&context);
1129 if ( code ) goto cleanup;
1131 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1132 if ( code ) goto cleanup;
1134 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1136 userrealm = strchr(username,'@');
1138 pname = strdup(username);
1139 if (!KFW_accept_dotted_usernames()) {
1140 userrealm = strchr(pname, '@');
1143 /* handle kerberos iv notation */
1144 while ( dot = strchr(pname,'.') ) {
1151 size_t len = strlen(username) + strlen(realm) + 2;
1152 pname = malloc(len);
1153 if (pname == NULL) {
1154 code = KRB5KRB_ERR_GENERIC;
1157 StringCbCopy(pname, len, username);
1159 if (!KFW_accept_dotted_usernames()) {
1160 /* handle kerberos iv notation */
1161 while ( dot = strchr(pname,'.') ) {
1165 StringCbCat( pname, len, "@");
1166 StringCbCat( pname, len, realm);
1168 if ( IsDebuggerPresent() ) {
1169 OutputDebugString("Realm of Cell: ");
1170 OutputDebugString(realm);
1171 OutputDebugString("\n");
1172 OutputDebugString("Realm of User: ");
1173 OutputDebugString(userrealm?userrealm:"<NULL>");
1174 OutputDebugString("\n");
1177 code = krb5_parse_name(context, pname, &principal);
1178 if ( code ) goto cleanup;
1180 code = KFW_get_ccache(context, principal, &cc);
1181 if ( code ) goto cleanup;
1183 if ( lifetime == 0 )
1184 lifetime = KFW_get_default_lifetime(context, realm);
1186 if ( password && password[0] ) {
1187 code = KFW_kinit( context, cc, HWND_DESKTOP,
1192 0, /* forwardable */
1193 0, /* not proxiable */
1195 1, /* noaddresses */
1196 0 /* no public ip */
1198 pLeash_get_default_forwardable(),
1199 pLeash_get_default_proxiable(),
1200 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1201 pLeash_get_default_noaddresses(),
1202 pLeash_get_default_publicip()
1203 #endif /* USE_LEASH */
1206 if ( IsDebuggerPresent() ) {
1208 StringCbPrintf(message, sizeof(message), "KFW_kinit() returns: %d\n", code);
1209 OutputDebugString(message);
1211 if ( code ) goto cleanup;
1213 KFW_AFS_update_princ_ccache_data(context, cc, FALSE);
1215 code = KFW_AFS_klog(context, cc, "afs", cell, realm, lifetime, smbname);
1216 if ( IsDebuggerPresent() ) {
1218 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1219 OutputDebugString(message);
1221 if ( code ) goto cleanup;
1224 KFW_AFS_update_cell_princ_map(context, cell, pname, TRUE);
1226 // Attempt to obtain new tokens for other cells supported by the same
1228 cell_count = KFW_AFS_find_cells_for_princ(context, pname, &cells, TRUE);
1229 if ( cell_count > 1 ) {
1230 while ( cell_count-- ) {
1231 if ( strcmp(cells[cell_count],cell) ) {
1232 if ( IsDebuggerPresent() ) {
1234 StringCbPrintf(message, sizeof(message),
1235 "found another cell for the same principal: %s\n", cell);
1236 OutputDebugString(message);
1239 if (cellconfig.linkedCell) {
1240 free(cellconfig.linkedCell);
1241 cellconfig.linkedCell = NULL;
1243 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1244 if ( code ) continue;
1246 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1247 if ( IsDebuggerPresent() ) {
1248 OutputDebugString("Realm: ");
1249 OutputDebugString(realm);
1250 OutputDebugString("\n");
1253 code = KFW_AFS_klog(context, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1254 if ( IsDebuggerPresent() ) {
1256 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1257 OutputDebugString(message);
1260 free(cells[cell_count]);
1263 } else if ( cell_count == 1 ) {
1272 krb5_cc_close(context, cc);
1273 if ( cellconfig.linkedCell )
1274 free(cellconfig.linkedCell);
1276 if ( code && reasonP ) {
1277 const char *msg = krb5_get_error_message(context, code);
1278 StringCbCopyN( reason, sizeof(reason),
1279 msg, sizeof(reason) - 1);
1281 krb5_free_error_message(context, msg);
1287 KFW_AFS_destroy_tickets_for_cell(char * cell)
1289 krb5_context context = NULL;
1290 krb5_error_code code;
1292 char ** principals = NULL;
1294 DebugPrintf("KFW_AFS_destroy_tickets_for_cell: %s\n", cell);
1296 code = krb5_init_context(&context);
1297 if (code) context = 0;
1299 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, FALSE);
1301 krb5_principal princ = 0;
1305 int cell_count = KFW_AFS_find_cells_for_princ(context, principals[count], NULL, TRUE);
1306 if ( cell_count > 1 ) {
1307 // TODO - What we really should do here is verify whether or not any of the
1308 // other cells which use this principal to obtain its credentials actually
1309 // have valid tokens or not. If they are currently using these credentials
1310 // we will skip them. For the time being we assume that if there is an active
1311 // map in the table that they are actively being used.
1315 code = krb5_parse_name(context, principals[count], &princ);
1316 if (code) goto loop_cleanup;
1318 code = KFW_get_ccache(context, princ, &cc);
1319 if (code) goto loop_cleanup;
1321 code = krb5_cc_destroy(context, cc);
1326 krb5_cc_close(context, cc);
1330 krb5_free_principal(context, princ);
1334 KFW_AFS_update_cell_princ_map(context, cell, principals[count], FALSE);
1335 free(principals[count]);
1340 krb5_free_context(context);
1345 KFW_AFS_destroy_tickets_for_principal(char * user)
1347 krb5_context context = NULL;
1348 krb5_error_code code;
1350 char ** cells = NULL;
1351 krb5_principal princ = NULL;
1352 krb5_ccache cc = NULL;
1354 DebugPrintf("KFW_AFS_destroy_tickets_for_user: %s\n", user);
1356 code = krb5_init_context(&context);
1359 code = krb5_parse_name(context, user, &princ);
1360 if (code) goto loop_cleanup;
1362 code = KFW_get_ccache(context, princ, &cc);
1363 if (code) goto loop_cleanup;
1365 code = krb5_cc_destroy(context, cc);
1370 krb5_cc_close(context, cc);
1374 krb5_free_principal(context, princ);
1378 count = KFW_AFS_find_cells_for_princ(context, user, &cells, TRUE);
1381 KFW_AFS_update_cell_princ_map(context, cells[count], user, FALSE);
1388 krb5_free_context(context);
1394 KFW_AFS_renew_expiring_tokens(void)
1396 krb5_error_code code = 0;
1397 krb5_context context = NULL;
1398 krb5_ccache cc = NULL;
1400 struct principal_ccache_data * pcc_next = princ_cc_data;
1403 const char * realm = NULL;
1404 char local_cell[CELL_MAXNAMELEN+1]="";
1405 struct afsconf_cell cellconfig;
1407 if ( pcc_next == NULL ) // nothing to do
1410 if ( IsDebuggerPresent() ) {
1411 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1414 memset(&cellconfig, 0, sizeof(cellconfig));
1416 code = krb5_init_context(&context);
1417 if (code) goto cleanup;
1419 code = krb5_timeofday(context, &now);
1420 if (code) goto cleanup;
1422 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1423 if ( pcc_next->expired )
1426 if ( now >= (pcc_next->expiration_time) ) {
1427 if ( !pcc_next->from_lsa ) {
1428 pcc_next->expired = 1;
1433 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1434 code = krb5_cc_resolve(context, pcc_next->ccache_name, &cc);
1437 code = KFW_renew(context,cc);
1439 if ( code && pcc_next->from_lsa)
1441 #endif /* USE_MS2MIT */
1444 KFW_AFS_update_princ_ccache_data(context, cc, pcc_next->from_lsa);
1445 if (code) goto loop_cleanup;
1447 // Attempt to obtain new tokens for other cells supported by the same
1449 cell_count = KFW_AFS_find_cells_for_princ(context, pcc_next->principal, &cells, TRUE);
1450 if ( cell_count > 0 ) {
1451 while ( cell_count-- ) {
1452 if ( IsDebuggerPresent() ) {
1453 OutputDebugString("Cell: ");
1454 OutputDebugString(cells[cell_count]);
1455 OutputDebugString("\n");
1457 if (cellconfig.linkedCell) {
1458 free(cellconfig.linkedCell);
1459 cellconfig.linkedCell = NULL;
1461 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1462 if ( code ) continue;
1463 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1464 if ( IsDebuggerPresent() ) {
1465 OutputDebugString("Realm: ");
1466 OutputDebugString(realm);
1467 OutputDebugString("\n");
1469 code = KFW_AFS_klog(context, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1470 if ( IsDebuggerPresent() ) {
1472 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1473 OutputDebugString(message);
1475 free(cells[cell_count]);
1483 krb5_cc_close(context,cc);
1490 krb5_cc_close(context,cc);
1492 krb5_free_context(context);
1493 if (cellconfig.linkedCell)
1494 free(cellconfig.linkedCell);
1501 KFW_AFS_renew_token_for_cell(char * cell)
1503 krb5_error_code code = 0;
1504 krb5_context context = NULL;
1506 char ** principals = NULL;
1508 if ( IsDebuggerPresent() ) {
1509 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1510 OutputDebugString(cell);
1511 OutputDebugString("\n");
1514 code = krb5_init_context(&context);
1515 if (code) goto cleanup;
1517 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, TRUE);
1519 // We know we must have a credential somewhere since we are
1520 // trying to renew a token
1522 KFW_import_ccache_data();
1523 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, TRUE);
1526 krb5_principal princ = 0;
1527 krb5_principal service = 0;
1529 krb5_creds mcreds, creds;
1530 #endif /* COMMENT */
1532 const char * realm = NULL;
1533 struct afsconf_cell cellconfig;
1534 char local_cell[CELL_MAXNAMELEN+1];
1536 memset(&cellconfig, 0, sizeof(cellconfig));
1539 code = krb5_parse_name(context, principals[count], &princ);
1540 if (code) goto loop_cleanup;
1542 code = KFW_get_ccache(context, princ, &cc);
1543 if (code) goto loop_cleanup;
1545 if (cellconfig.linkedCell) {
1546 free(cellconfig.linkedCell);
1547 cellconfig.linkedCell = NULL;
1549 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1550 if ( code ) goto loop_cleanup;
1552 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1553 if ( IsDebuggerPresent() ) {
1554 OutputDebugString("Realm: ");
1555 OutputDebugString(realm);
1556 OutputDebugString("\n");
1560 /* krb5_cc_remove_cred() is not implemented
1563 code = krb5_build_principal(context, &service, strlen(realm),
1564 realm, "afs", cell, NULL);
1566 memset(&mcreds, 0, sizeof(krb5_creds));
1567 mcreds.client = princ;
1568 mcreds.server = service;
1570 code = krb5_cc_retrieve_cred(context, cc, 0, &mcreds, &creds);
1572 if ( IsDebuggerPresent() ) {
1573 char * cname, *sname;
1574 krb5_unparse_name(context, creds.client, &cname);
1575 krb5_unparse_name(context, creds.server, &sname);
1576 OutputDebugString("Removing credential for client \"");
1577 OutputDebugString(cname);
1578 OutputDebugString("\" and service \"");
1579 OutputDebugString(sname);
1580 OutputDebugString("\"\n");
1581 krb5_free_unparsed_name(context,cname);
1582 krb5_free_unparsed_name(context,sname);
1585 code = krb5_cc_remove_cred(context, cc, 0, &creds);
1586 krb5_free_principal(context, creds.client);
1587 krb5_free_principal(context, creds.server);
1590 #endif /* COMMENT */
1592 code = KFW_AFS_klog(context, cc, "afs", cell, (char *)realm, 0,NULL);
1593 if ( IsDebuggerPresent() ) {
1595 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1596 OutputDebugString(message);
1601 krb5_cc_close(context, cc);
1605 krb5_free_principal(context, princ);
1609 krb5_free_principal(context, service);
1612 if (cellconfig.linkedCell) {
1613 free(cellconfig.linkedCell);
1614 cellconfig.linkedCell = NULL;
1617 KFW_AFS_update_cell_princ_map(context, cell, principals[count], code ? FALSE : TRUE);
1618 free(principals[count]);
1622 code = -1; // we did not renew the tokens
1626 krb5_free_context(context);
1627 return (code ? FALSE : TRUE);
1632 KFW_AFS_renew_tokens_for_all_cells(void)
1634 struct cell_principal_map * next = cell_princ_map;
1636 DebugPrintf("KFW_AFS_renew_tokens_for_all()\n");
1641 for ( ; next ; next = next->next ) {
1643 KFW_AFS_renew_token_for_cell(next->cell);
1649 KFW_renew(krb5_context alt_context, krb5_ccache alt_cc)
1651 krb5_error_code code = 0;
1652 krb5_context context = NULL;
1653 krb5_ccache cc = NULL;
1654 krb5_principal me = NULL;
1655 krb5_principal server = NULL;
1656 krb5_creds my_creds;
1657 const char *realm = NULL;
1659 memset(&my_creds, 0, sizeof(krb5_creds));
1661 if ( alt_context ) {
1662 context = alt_context;
1664 code = krb5_init_context(&context);
1665 if (code) goto cleanup;
1671 code = krb5_cc_default(context, &cc);
1672 if (code) goto cleanup;
1675 code = krb5_cc_get_principal(context, cc, &me);
1676 if (code) goto cleanup;
1678 realm = krb5_principal_get_realm(context, me);
1680 code = krb5_make_principal(context, &server, realm,
1681 KRB5_TGS_NAME, realm, NULL);
1685 if ( IsDebuggerPresent() ) {
1686 char * cname, *sname;
1687 krb5_unparse_name(context, me, &cname);
1688 krb5_unparse_name(context, server, &sname);
1689 DebugPrintf("Renewing credential for client \"%s\" and service\"%s\"\n",
1691 krb5_free_unparsed_name(context,cname);
1692 krb5_free_unparsed_name(context,sname);
1695 my_creds.client = me;
1696 my_creds.server = server;
1698 code = krb5_get_renewed_creds(context, &my_creds, me, cc, NULL);
1700 DebugPrintf("krb5_get_renewed_creds() failed: %d\n", code);
1704 code = krb5_cc_initialize(context, cc, me);
1706 DebugPrintf("krb5_cc_initialize() failed: %d\n", code);
1710 code = krb5_cc_store_cred(context, cc, &my_creds);
1712 DebugPrintf("krb5_cc_store_cred() failed: %d\n", code);
1717 if (my_creds.client == me)
1718 my_creds.client = 0;
1719 if (my_creds.server == server)
1720 my_creds.server = 0;
1721 krb5_free_cred_contents(context, &my_creds);
1723 krb5_free_principal(context, me);
1725 krb5_free_principal(context, server);
1726 if (cc && (cc != alt_cc))
1727 krb5_cc_close(context, cc);
1728 if (context && (context != alt_context))
1729 krb5_free_context(context);
1734 KFW_kinit( krb5_context alt_context,
1737 char *principal_name,
1739 krb5_deltat lifetime,
1742 krb5_deltat renew_life,
1746 krb5_error_code code = 0;
1747 krb5_context context = NULL;
1748 krb5_ccache cc = NULL;
1749 krb5_principal me = NULL;
1751 krb5_creds my_creds;
1752 krb5_get_init_creds_opt *options = NULL;
1753 krb5_addresses addrs = {0, NULL};
1754 int i = 0, addr_count = 0;
1756 memset(&my_creds, 0, sizeof(my_creds));
1759 context = alt_context;
1761 code = krb5_init_context(&context);
1762 if (code) goto cleanup;
1768 code = krb5_cc_default(context, &cc);
1769 if (code) goto cleanup;
1772 code = krb5_get_init_creds_opt_alloc(context, &options);
1773 if (code) goto cleanup;
1775 code = krb5_parse_name(context, principal_name, &me);
1776 if (code) goto cleanup;
1778 code = krb5_unparse_name(context, me, &name);
1779 if (code) goto cleanup;
1782 lifetime = KFW_get_default_lifetime(context,
1783 krb5_principal_get_realm(context, me));
1791 krb5_get_init_creds_opt_set_tkt_life(options, lifetime);
1792 krb5_get_init_creds_opt_set_forwardable(options, forwardable ? 1 : 0);
1793 krb5_get_init_creds_opt_set_proxiable(options, proxiable ? 1 : 0);
1794 krb5_get_init_creds_opt_set_renew_life(options, renew_life);
1796 krb5_get_init_creds_opt_set_addressless(context, options, TRUE);
1799 // we are going to add the public IP address specified by the user
1800 // to the list provided by the operating system
1801 struct sockaddr_in in_addr;
1803 krb5_addresses addr_l;
1805 krb5_get_all_client_addrs(context, &addrs);
1807 in_addr.sin_family = AF_INET;
1808 in_addr.sin_port = 0;
1809 in_addr.sin_addr.S_un.S_addr = htonl(publicIP);
1811 code = krb5_sockaddr2address(context, (struct sockaddr *)&in_addr,
1818 code = krb5_append_addresses(context, &addrs, &addr_l);
1820 krb5_free_address(context, &addr);
1823 krb5_get_init_creds_opt_set_address_list(options, &addrs);
1827 code = krb5_get_init_creds_password(context,
1830 password, // password
1831 KRB5_prompter, // prompter
1832 hParent, // prompter data
1839 code = krb5_cc_initialize(context, cc, me);
1843 code = krb5_cc_store_cred(context, cc, &my_creds);
1848 if ( addrs.len > 0 )
1849 krb5_free_addresses(context, &addrs);
1851 if (my_creds.client == me)
1852 my_creds.client = 0;
1854 krb5_free_cred_contents(context, &my_creds);
1856 krb5_free_unparsed_name(context, name);
1858 krb5_free_principal(context, me);
1860 krb5_get_init_creds_opt_free(context, options);
1861 if (cc && (cc != alt_cc))
1862 krb5_cc_close(context, cc);
1863 if (context && (context != alt_context))
1864 krb5_free_context(context);
1870 KFW_kdestroy(krb5_context alt_context, krb5_ccache alt_cc)
1872 krb5_context context = NULL;
1873 krb5_ccache cc = NULL;
1874 krb5_error_code code;
1877 context = alt_context;
1879 code = krb5_init_context(&context);
1880 if (code) goto cleanup;
1886 code = krb5_cc_default(context, &cc);
1887 if (code) goto cleanup;
1890 code = krb5_cc_destroy(context, cc);
1891 if ( !code ) cc = 0;
1894 if (cc && (cc != alt_cc))
1895 krb5_cc_close(context, cc);
1896 if (context && (context != alt_context))
1897 krb5_free_context(context);
1905 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1907 NTSTATUS Status = 0;
1909 TOKEN_STATISTICS Stats;
1915 *ppSessionData = NULL;
1917 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1921 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1922 CloseHandle( TokenHandle );
1926 Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1927 if ( FAILED(Status) || !ppSessionData )
1934 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
1935 // cache. It validates whether or not it is reasonable to assume that if we
1936 // attempted to retrieve valid tickets we could do so. Microsoft does not
1937 // automatically renew expired tickets. Therefore, the cache could contain
1938 // expired or invalid tickets. Microsoft also caches the user's password
1939 // and will use it to retrieve new TGTs if the cache is empty and tickets
1943 MSLSA_IsKerberosLogon(VOID)
1945 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
1946 BOOL Success = FALSE;
1948 if ( GetSecurityLogonSessionData(&pSessionData) ) {
1949 if ( pSessionData->AuthenticationPackage.Buffer ) {
1955 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
1956 usLength = (pSessionData->AuthenticationPackage).Length;
1959 StringCbCopyNW( buffer, sizeof(buffer)/sizeof(WCHAR),
1960 usBuffer, usLength);
1961 if ( !lstrcmpW(L"Kerberos",buffer) )
1965 LsaFreeReturnBuffer(pSessionData);
1969 #endif /* USE_MS2MIT */
1971 static BOOL CALLBACK
1972 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
1976 switch ( message ) {
1978 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
1980 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
1983 for ( i=0; i < mid_cnt ; i++ ) {
1984 if (mid_tb[i].echo == 0)
1985 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
1986 else if (mid_tb[i].echo == 2)
1987 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
1992 switch ( LOWORD(wParam) ) {
1994 for ( i=0; i < mid_cnt ; i++ ) {
1995 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
1996 *mid_tb[i].buf = '\0';
2000 EndDialog(hDialog, LOWORD(wParam));
2008 lpwAlign( LPWORD lpIn )
2012 ul = (ULONG_PTR) lpIn;
2016 return (LPWORD) ul;;
2020 * dialog widths are measured in 1/4 character widths
2021 * dialog height are measured in 1/8 character heights
2025 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2026 char * ptext[], int numlines, int width,
2027 int tb_cnt, struct textField * tb)
2031 LPDLGITEMTEMPLATE lpdit;
2037 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2044 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2046 // Define a dialog box.
2048 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2049 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2050 | DS_SETFOREGROUND | DS_3DLOOK
2051 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2052 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2055 lpdt->cx = 20 + width * 4;
2056 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2058 lpw = (LPWORD) (lpdt + 1);
2059 *lpw++ = 0; // no menu
2060 *lpw++ = 0; // predefined dialog box class (by default)
2062 lpwsz = (LPWSTR) lpw;
2063 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2065 *lpw++ = 8; // font size (points)
2066 lpwsz = (LPWSTR) lpw;
2067 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2071 //-----------------------
2072 // Define an OK button.
2073 //-----------------------
2074 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2075 lpdit = (LPDLGITEMTEMPLATE) lpw;
2076 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2077 lpdit->dwExtendedStyle = 0;
2078 lpdit->x = (lpdt->cx - 14)/4 - 20;
2079 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2082 lpdit->id = IDOK; // OK button identifier
2084 lpw = (LPWORD) (lpdit + 1);
2086 *lpw++ = 0x0080; // button class
2088 lpwsz = (LPWSTR) lpw;
2089 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2091 *lpw++ = 0; // no creation data
2093 //-----------------------
2094 // Define an Cancel button.
2095 //-----------------------
2096 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2097 lpdit = (LPDLGITEMTEMPLATE) lpw;
2098 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2099 lpdit->dwExtendedStyle = 0;
2100 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2101 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2104 lpdit->id = IDCANCEL; // CANCEL button identifier
2106 lpw = (LPWORD) (lpdit + 1);
2108 *lpw++ = 0x0080; // button class
2110 lpwsz = (LPWSTR) lpw;
2111 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2113 *lpw++ = 0; // no creation data
2115 /* Add controls for preface data */
2116 for ( i=0; i<numlines; i++) {
2117 /*-----------------------
2118 * Define a static text control.
2119 *-----------------------*/
2120 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2121 lpdit = (LPDLGITEMTEMPLATE) lpw;
2122 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2123 lpdit->dwExtendedStyle = 0;
2125 lpdit->y = 10 + i * 14;
2126 lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2128 lpdit->id = ID_TEXT + i; // text identifier
2130 lpw = (LPWORD) (lpdit + 1);
2132 *lpw++ = 0x0082; // static class
2134 lpwsz = (LPWSTR) lpw;
2135 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2136 -1, lpwsz, 2*width);
2138 *lpw++ = 0; // no creation data
2141 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2142 int len = (int)strlen(tb[i].label);
2147 for ( i=0; i<tb_cnt; i++) {
2149 /*-----------------------
2150 * Define a static text control.
2151 *-----------------------*/
2152 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2153 lpdit = (LPDLGITEMTEMPLATE) lpw;
2154 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2155 lpdit->dwExtendedStyle = 0;
2157 lpdit->y = 10 + (numlines + i + 1) * 14;
2158 lpdit->cx = pwid * 4;
2160 lpdit->id = ID_TEXT + numlines + i; // text identifier
2162 lpw = (LPWORD) (lpdit + 1);
2164 *lpw++ = 0x0082; // static class
2166 lpwsz = (LPWSTR) lpw;
2167 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2170 *lpw++ = 0; // no creation data
2172 /*-----------------------
2173 * Define an edit control.
2174 *-----------------------*/
2175 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2176 lpdit = (LPDLGITEMTEMPLATE) lpw;
2177 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2178 lpdit->dwExtendedStyle = 0;
2179 lpdit->x = 10 + (pwid + 1) * 4;
2180 lpdit->y = 10 + (numlines + i + 1) * 14;
2181 lpdit->cx = (width - (pwid + 1)) * 4;
2183 lpdit->id = ID_MID_TEXT + i; // identifier
2185 lpw = (LPWORD) (lpdit + 1);
2187 *lpw++ = 0x0081; // edit class
2189 lpwsz = (LPWSTR) lpw;
2190 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2193 *lpw++ = 0; // no creation data
2197 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2198 hwndOwner, (DLGPROC) MultiInputDialogProc);
2202 case 0: /* Timeout */
2210 StringCbPrintf(buf, sizeof(buf), "DialogBoxIndirect() failed: %d", GetLastError());
2211 MessageBox(hwndOwner,
2214 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2221 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2223 HINSTANCE hInst = 0;
2224 size_t maxwidth = 0;
2227 char * plines[16], *p = preface ? preface : "";
2230 for ( i=0; i<16; i++ )
2233 while (*p && numlines < 16) {
2234 plines[numlines++] = p;
2235 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2236 if ( *p == '\r' && *(p+1) == '\n' ) {
2239 } else if ( *p == '\n' ) {
2242 if ( strlen(plines[numlines-1]) > maxwidth )
2243 maxwidth = strlen(plines[numlines-1]);
2246 for ( i=0;i<n;i++ ) {
2247 len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2248 if ( maxwidth < len )
2252 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2255 static krb5_error_code KRB5_CALLCONV
2256 KRB5_prompter( krb5_context context,
2261 krb5_prompt prompts[])
2263 krb5_error_code errcode = 0;
2265 struct textField * tb = NULL;
2266 int len = 0, blen=0, nlen=0;
2267 HWND hParent = (HWND)data;
2270 nlen = (int)strlen(name)+2;
2273 blen = (int)strlen(banner)+2;
2275 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2278 memset(tb,0,sizeof(struct textField) * num_prompts);
2279 for ( i=0; i < num_prompts; i++ ) {
2280 tb[i].buf = prompts[i].reply->data;
2281 tb[i].len = prompts[i].reply->length;
2282 tb[i].label = prompts[i].prompt;
2284 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2287 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2289 for ( i=0; i < num_prompts; i++ )
2290 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2298 for (i = 0; i < num_prompts; i++) {
2299 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2306 KFW_AFS_wait_for_service_start(void)
2311 CurrentState = SERVICE_START_PENDING;
2312 memset(HostName, '\0', sizeof(HostName));
2313 gethostname(HostName, sizeof(HostName));
2315 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2317 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2319 if ( IsDebuggerPresent() ) {
2320 switch ( CurrentState ) {
2321 case SERVICE_STOPPED:
2322 OutputDebugString("SERVICE_STOPPED\n");
2324 case SERVICE_START_PENDING:
2325 OutputDebugString("SERVICE_START_PENDING\n");
2327 case SERVICE_STOP_PENDING:
2328 OutputDebugString("SERVICE_STOP_PENDING\n");
2330 case SERVICE_RUNNING:
2331 OutputDebugString("SERVICE_RUNNING\n");
2333 case SERVICE_CONTINUE_PENDING:
2334 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2336 case SERVICE_PAUSE_PENDING:
2337 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2339 case SERVICE_PAUSED:
2340 OutputDebugString("SERVICE_PAUSED\n");
2343 OutputDebugString("UNKNOWN Service State\n");
2346 if (CurrentState == SERVICE_STOPPED)
2348 if (CurrentState == SERVICE_RUNNING)
2364 memset(HostName, '\0', sizeof(HostName));
2365 gethostname(HostName, sizeof(HostName));
2366 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2368 if (CurrentState != SERVICE_RUNNING)
2371 rc = ktc_ForgetAllTokens();
2377 #define ALLOW_REGISTER 1
2379 ViceIDToUsername(char *username,
2380 char *realm_of_user,
2381 char *realm_of_cell,
2383 struct ktc_principal *aclient,
2384 struct ktc_principal *aserver,
2385 struct ktc_token *atoken)
2387 static char lastcell[CELL_MAXNAMELEN+1] = { 0 };
2388 static char confdir[512] = { 0 };
2389 #ifdef AFS_ID_TO_NAME
2390 char username_copy[BUFSIZ];
2391 #endif /* AFS_ID_TO_NAME */
2392 long viceId = ANONYMOUSID; /* AFS uid of user */
2394 #ifdef ALLOW_REGISTER
2396 #endif /* ALLOW_REGISTER */
2398 if (confdir[0] == '\0')
2399 cm_GetConfigDir(confdir, sizeof(confdir));
2401 StringCbCopyN( lastcell, sizeof(lastcell),
2402 aserver->cell, sizeof(lastcell) - 1);
2404 if (!pr_Initialize (0, confdir, aserver->cell)) {
2405 char sname[PR_MAXNAMELEN];
2406 StringCbCopyN( sname, sizeof(sname),
2407 username, sizeof(sname) - 1);
2408 status = pr_SNameToId (sname, &viceId);
2413 * This is a crock, but it is Transarc's crock, so
2414 * we have to play along in order to get the
2415 * functionality. The way the afs id is stored is
2416 * as a string in the username field of the token.
2417 * Contrary to what you may think by looking at
2418 * the code for tokens, this hack (AFS ID %d) will
2419 * not work if you change %d to something else.
2423 * This code is taken from cklog -- it lets people
2424 * automatically register with the ptserver in foreign cells
2427 #ifdef ALLOW_REGISTER
2429 if (viceId != ANONYMOUSID) {
2430 #else /* ALLOW_REGISTER */
2431 if ((status == 0) && (viceId != ANONYMOUSID))
2432 #endif /* ALLOW_REGISTER */
2434 #ifdef AFS_ID_TO_NAME
2435 StringCbCopyN( username_copy, sizeof(username_copy),
2436 username, sizeof(username_copy) - 1);
2437 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2438 #endif /* AFS_ID_TO_NAME */
2440 #ifdef ALLOW_REGISTER
2441 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2443 StringCbCopyN( aclient->name, sizeof(aclient->name),
2444 username, sizeof(aclient->name) - 1);
2445 aclient->instance[0] = '\0';
2446 StringCbCopyN( aclient->cell, sizeof(aclient->cell),
2447 realm_of_user, sizeof(aclient->cell) - 1);
2448 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2450 if (status = pr_Initialize(1L, confdir, aserver->cell))
2452 status = pr_CreateUser(username, &id);
2456 #ifdef AFS_ID_TO_NAME
2457 StringCbCopyN( username_copy, sizeof(username_copy),
2458 username, sizeof(username_copy) - 1);
2459 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2460 #endif /* AFS_ID_TO_NAME */
2463 #endif /* ALLOW_REGISTER */
2469 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
2474 ret = decode_Ticket(v5cred->ticket.data, v5cred->ticket.length,
2477 StringCbCopy(dest, destlen, ticket.realm);
2479 free_Ticket(&ticket);
2484 KFW_AFS_continue_aklog_processing_after_krb5_error(krb5_error_code code)
2486 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2487 code == KRB5_ERR_HOST_REALM_UNKNOWN ||
2488 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2489 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2498 krb5_context alt_context,
2503 int lifetime, /* unused parameter */
2508 struct ktc_principal aserver;
2509 struct ktc_principal aclient;
2510 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2511 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2512 char local_cell[CELL_MAXNAMELEN+1];
2513 char Dmycell[CELL_MAXNAMELEN+1];
2514 struct ktc_token atoken;
2515 struct ktc_token btoken;
2516 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2517 char RealmName[128];
2519 char ServiceName[128];
2522 krb5_context context = NULL;
2523 krb5_ccache cc = NULL;
2525 krb5_creds * k5creds = NULL;
2526 krb5_error_code code;
2527 krb5_principal client_principal = NULL;
2528 krb5_data * k5data = NULL;
2529 unsigned int retry = 0;
2532 memset(HostName, '\0', sizeof(HostName));
2533 gethostname(HostName, sizeof(HostName));
2534 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2535 if ( IsDebuggerPresent() )
2536 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2539 if (CurrentState != SERVICE_RUNNING) {
2540 if ( IsDebuggerPresent() )
2541 OutputDebugString("AFSD Service NOT RUNNING\n");
2545 memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
2546 memset(RealmName, '\0', sizeof(RealmName));
2547 memset(CellName, '\0', sizeof(CellName));
2548 memset(ServiceName, '\0', sizeof(ServiceName));
2549 memset(realm_of_user, '\0', sizeof(realm_of_user));
2550 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2551 if (cell && cell[0])
2552 StringCbCopyN( Dmycell, sizeof(Dmycell),
2553 cell, sizeof(Dmycell) - 1);
2555 memset(Dmycell, '\0', sizeof(Dmycell));
2557 // NULL or empty cell returns information on local cell
2558 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2560 // KFW_AFS_error(rc, "get_cellconfig()");
2564 if ( alt_context ) {
2565 context = alt_context;
2567 code = krb5_init_context(&context);
2568 if (code) goto cleanup;
2574 code = krb5_cc_default(context, &cc);
2579 memset(&increds, 0, sizeof(increds));
2581 code = krb5_cc_get_principal(context, cc, &client_principal);
2583 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2585 OutputDebugString("Principal Not Found for ccache\n");
2590 if (!KFW_accept_dotted_usernames()) {
2592 /* look for client principals which cannot be distinguished
2593 * from Kerberos 4 multi-component principal names
2595 comp = krb5_principal_get_comp_string(context,client_principal,0);
2596 if (strchr(comp, '.') != NULL) {
2597 OutputDebugString("Illegal Principal name contains dot in first component\n");
2598 rc = KRB5KRB_ERR_GENERIC;
2603 StringCbCopy(realm_of_user, sizeof(realm_of_user),
2604 krb5_principal_get_realm(context, client_principal));
2606 StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
2607 afs_realm_of_cell(context, &ak_cellconfig),
2608 sizeof(realm_of_cell) - 1);
2610 if (strlen(service) == 0)
2611 StringCbCopy( ServiceName, sizeof(ServiceName), "afs");
2613 StringCbCopyN( ServiceName, sizeof(ServiceName),
2614 service, sizeof(ServiceName) - 1);
2616 if (strlen(cell) == 0)
2617 StringCbCopyN( CellName, sizeof(CellName),
2618 local_cell, sizeof(CellName) - 1);
2620 StringCbCopyN( CellName, sizeof(CellName),
2621 cell, sizeof(CellName) - 1);
2623 if (strlen(realm) == 0)
2624 StringCbCopyN( RealmName, sizeof(RealmName),
2625 realm_of_cell, sizeof(RealmName) - 1);
2627 StringCbCopyN( RealmName, sizeof(RealmName),
2628 realm, sizeof(RealmName) - 1);
2630 code = KRB5KRB_ERR_GENERIC;
2632 increds.client = client_principal;
2633 increds.times.endtime = 0;
2635 /* ALWAYS first try service/cell@CLIENT_REALM */
2636 if (code = krb5_build_principal(context, &increds.server,
2637 (int)strlen(realm_of_user),
2646 if ( IsDebuggerPresent() ) {
2647 char * cname, *sname;
2648 krb5_unparse_name(context, increds.client, &cname);
2649 krb5_unparse_name(context, increds.server, &sname);
2650 OutputDebugString("Getting tickets for \"");
2651 OutputDebugString(cname);
2652 OutputDebugString("\" and service \"");
2653 OutputDebugString(sname);
2654 OutputDebugString("\"\n");
2655 krb5_free_unparsed_name(context,cname);
2656 krb5_free_unparsed_name(context,sname);
2659 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2662 * The client's realm is a local realm for the cell.
2663 * Save it so that later the pts registration will not
2666 StringCbCopyN(realm_of_cell, sizeof(realm_of_cell),
2667 realm_of_user, sizeof(realm_of_cell) - 1);
2670 if (KFW_AFS_continue_aklog_processing_after_krb5_error(code)) {
2671 if (strcmp(realm_of_user, RealmName)) {
2672 /* service/cell@REALM */
2674 code = krb5_build_principal(context, &increds.server,
2675 (int)strlen(RealmName),
2681 if ( IsDebuggerPresent() ) {
2682 char * cname, *sname;
2683 krb5_unparse_name(context, increds.client, &cname);
2684 krb5_unparse_name(context, increds.server, &sname);
2685 OutputDebugString("Getting tickets for \"");
2686 OutputDebugString(cname);
2687 OutputDebugString("\" and service \"");
2688 OutputDebugString(sname);
2689 OutputDebugString("\"\n");
2690 krb5_free_unparsed_name(context,cname);
2691 krb5_free_unparsed_name(context,sname);
2695 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2698 if (KFW_AFS_continue_aklog_processing_after_krb5_error(code)) {
2699 /* Or service@REALM */
2700 krb5_free_principal(context,increds.server);
2702 code = krb5_build_principal(context, &increds.server,
2703 (int)strlen(RealmName),
2708 if ( IsDebuggerPresent() ) {
2709 char * cname, *sname;
2710 krb5_unparse_name(context, increds.client, &cname);
2711 krb5_unparse_name(context, increds.server, &sname);
2712 DebugPrintf("Getting tickets for \"%s\" and service \"%s\"\n", cname, sname);
2713 krb5_free_unparsed_name(context,cname);
2714 krb5_free_unparsed_name(context,sname);
2718 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2723 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
2726 DebugPrintf("krb5_get_credentials returns: %d\n", code);
2730 /* This code inserts the entire K5 ticket into the token */
2731 memset(&aserver, '\0', sizeof(aserver));
2732 StringCbCopyN(aserver.name, sizeof(aserver.name),
2733 ServiceName, sizeof(aserver.name) - 1);
2734 StringCbCopyN(aserver.cell, sizeof(aserver.cell),
2735 CellName, sizeof(aserver.cell) - 1);
2737 memset(&atoken, '\0', sizeof(atoken));
2738 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2739 atoken.startTime = k5creds->times.starttime;
2740 atoken.endTime = k5creds->times.endtime;
2741 if (tkt_DeriveDesKey(k5creds->session.keytype, k5creds->session.keyvalue.data,
2742 k5creds->session.keyvalue.length, &atoken.sessionKey))
2744 atoken.ticketLen = k5creds->ticket.length;
2745 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2748 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2749 if ( IsDebuggerPresent() ) {
2751 StringCbPrintf(message, sizeof(message), "ktc_GetToken returns: %d\n", rc);
2752 OutputDebugString(message);
2754 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2755 if ( rc == KTC_NOCM && retry < 20 ) {
2758 goto retry_gettoken5;
2763 if (atoken.kvno == btoken.kvno &&
2764 atoken.ticketLen == btoken.ticketLen &&
2765 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2766 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2768 /* Success - Nothing to do */
2772 // * Reset the "aclient" structure before we call ktc_SetToken.
2773 // * This structure was first set by the ktc_GetToken call when
2774 // * we were comparing whether identical tokens already existed.
2776 StringCbCopy(aclient.name, sizeof(aclient.name),
2777 krb5_principal_get_comp_string(context, k5creds->client, 0));
2779 if ( krb5_principal_get_num_comp(context, k5creds->client) > 1 ) {
2780 StringCbCat(aclient.name, sizeof(aclient.name), ".");
2781 StringCbCat(aclient.name, sizeof(aclient.name),
2782 krb5_principal_get_comp_string(context, k5creds->client, 1));
2784 aclient.instance[0] = '\0';
2786 StringCbCopyN(aclient.cell, sizeof(aclient.cell),
2787 realm_of_cell, sizeof(aclient.cell) - 1);
2789 /* For Khimaira, always append the realm name */
2790 StringCbCat(aclient.name, sizeof(aclient.name), "@");
2791 StringCbCat(aclient.name, sizeof(aclient.name),
2792 krb5_principal_get_realm(context, k5creds->client));
2794 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
2795 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
2796 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
2797 &aclient, &aserver, &atoken);
2800 StringCbCopyN(aclient.smbname, sizeof(aclient.smbname),
2801 smbname, sizeof(aclient.smbname) - 1);
2803 aclient.smbname[0] = '\0';
2805 if ( IsDebuggerPresent() ) {
2807 StringCbPrintf(message, sizeof(message), "aclient.name: %s\n", aclient.name);
2808 OutputDebugString(message);
2809 StringCbPrintf(message, sizeof(message), "aclient.smbname: %s\n", aclient.smbname);
2810 OutputDebugString(message);
2813 rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
2816 if (client_principal)
2817 krb5_free_principal(context,client_principal);
2818 /* increds.client == client_principal */
2820 krb5_free_principal(context,increds.server);
2821 if (cc && (cc != alt_cc))
2822 krb5_cc_close(context, cc);
2823 if (context && (context != alt_context))
2824 krb5_free_context(context);
2825 if (ak_cellconfig.linkedCell)
2826 free(ak_cellconfig.linkedCell);
2828 return(rc? rc : code);
2831 /**************************************/
2832 /* afs_realm_of_cell(): */
2833 /**************************************/
2835 afs_realm_of_cell(krb5_context context, struct afsconf_cell *cellconfig)
2837 static char krbrlm[REALM_SZ+1]="";
2838 char ** realmlist=NULL;
2844 r = krb5_get_host_realm(context, cellconfig->hostName[0], &realmlist);
2845 if ( !r && realmlist && realmlist[0] ) {
2846 StringCbCopyN( krbrlm, sizeof(krbrlm),
2847 realmlist[0], sizeof(krbrlm) - 1);
2848 krb5_free_host_realm(context, realmlist);
2854 char *t = cellconfig->name;
2859 if (islower(c)) c=toupper(c);
2867 /**************************************/
2868 /* KFW_AFS_get_cellconfig(): */
2869 /**************************************/
2871 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
2874 char newcell[CELL_MAXNAMELEN+1];
2875 char linkedcell[CELL_MAXNAMELEN+1]="";
2877 local_cell[0] = (char)0;
2878 memset(cellconfig, 0, sizeof(*cellconfig));
2880 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
2881 if (rc = cm_GetRootCellName(local_cell))
2886 if (strlen(cell) == 0)
2887 StringCbCopy(cell, CELL_MAXNAMELEN, local_cell);
2889 rc = cm_SearchCellRegistry(1, cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
2890 if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
2891 rc = cm_SearchCellFileEx(cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
2894 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
2898 StringCbCopyN( cellconfig->name, sizeof(cellconfig->name),
2899 newcell, sizeof(cellconfig->name) - 1);
2901 cellconfig->linkedCell = strdup(linkedcell);
2906 /**************************************/
2907 /* get_cellconfig_callback(): */
2908 /**************************************/
2910 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep, unsigned short ipRank)
2912 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
2914 cc->hostAddr[cc->numServers] = *addrp;
2915 StringCbCopyN( cc->hostName[cc->numServers], sizeof(cc->hostName[cc->numServers]),
2916 namep, sizeof(cc->hostName[cc->numServers]) - 1);
2922 /**************************************/
2923 /* KFW_AFS_error(): */
2924 /**************************************/
2926 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
2929 const char *errText;
2931 // Using AFS defines as error messages for now, until Transarc
2932 // gets back to me with "string" translations of each of these
2934 if (rc == KTC_ERROR)
2935 errText = "KTC_ERROR";
2936 else if (rc == KTC_TOOBIG)
2937 errText = "KTC_TOOBIG";
2938 else if (rc == KTC_INVAL)
2939 errText = "KTC_INVAL";
2940 else if (rc == KTC_NOENT)
2941 errText = "KTC_NOENT";
2942 else if (rc == KTC_PIOCTLFAIL)
2943 errText = "KTC_PIOCTLFAIL";
2944 else if (rc == KTC_NOPIOCTL)
2945 errText = "KTC_NOPIOCTL";
2946 else if (rc == KTC_NOCELL)
2947 errText = "KTC_NOCELL";
2948 else if (rc == KTC_NOCM)
2949 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
2951 errText = "Unknown error!";
2953 StringCbPrintf(message, sizeof(message), "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
2955 if ( IsDebuggerPresent() ) {
2956 OutputDebugString(message);
2957 OutputDebugString("\n");
2959 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
2965 LPSTR lpszMachineName,
2966 LPSTR lpszServiceName,
2967 DWORD *lpdwCurrentState)
2970 SC_HANDLE schSCManager = NULL;
2971 SC_HANDLE schService = NULL;
2972 DWORD fdwDesiredAccess = 0;
2973 SERVICE_STATUS ssServiceStatus = {0};
2976 *lpdwCurrentState = 0;
2978 fdwDesiredAccess = GENERIC_READ;
2980 schSCManager = OpenSCManager(lpszMachineName,
2984 if(schSCManager == NULL)
2986 hr = GetLastError();
2990 schService = OpenService(schSCManager,
2994 if(schService == NULL)
2996 hr = GetLastError();
3000 fRet = QueryServiceStatus(schService,
3005 hr = GetLastError();
3009 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3013 CloseServiceHandle(schService);
3014 CloseServiceHandle(schSCManager);
3019 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3021 krb5_context context = NULL;
3022 krb5_ccache cc = NULL;
3023 krb5_error_code code;
3025 const char * realm = NULL;
3026 krb5_principal principal = NULL;
3027 char * pname = NULL;
3028 char password[PROBE_PASSWORD_LEN+1];
3029 BOOL serverReachable = 0;
3031 code = krb5_init_context(&context);
3032 if (code) goto cleanup;
3035 realm = afs_realm_of_cell(context, cellconfig); // do not free
3037 code = krb5_build_principal(context, &principal, (int)strlen(realm),
3038 realm, PROBE_USERNAME, NULL, NULL);
3039 if ( code ) goto cleanup;
3041 code = KFW_get_ccache(context, principal, &cc);
3042 if ( code ) goto cleanup;
3044 code = krb5_unparse_name(context, principal, &pname);
3045 if ( code ) goto cleanup;
3047 pwdata.data = password;
3048 pwdata.length = PROBE_PASSWORD_LEN;
3049 krb5_c_random_make_octets(context, &pwdata);
3052 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3053 if (password[i] == '\0')
3056 password[PROBE_PASSWORD_LEN] = '\0';
3058 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3068 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3069 case KRB5KDC_ERR_CLIENT_REVOKED:
3070 case KRB5KDC_ERR_CLIENT_NOTYET:
3071 case KRB5KDC_ERR_PREAUTH_FAILED:
3072 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3073 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3074 serverReachable = TRUE;
3077 serverReachable = FALSE;
3082 krb5_free_unparsed_name(context,pname);
3084 krb5_free_principal(context,principal);
3086 krb5_cc_close(context,cc);
3088 krb5_free_context(context);
3090 return serverReachable;
3094 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3096 krb5_context context = NULL;
3097 krb5_error_code code;
3098 krb5_ccache mslsa_ccache=NULL;
3099 krb5_principal princ = NULL;
3100 char * pname = NULL;
3103 if (!KFW_is_available())
3106 if (code = krb5_init_context(&context))
3109 if (code = krb5_cc_resolve(context, "MSLSA:", &mslsa_ccache))
3112 if (code = krb5_cc_get_principal(context, mslsa_ccache, &princ))
3115 if (code = krb5_unparse_name(context, princ, &pname))
3118 if ( strlen(pname) < *dwSize ) {
3119 StringCbCopyN(szUser, *dwSize, pname, (*dwSize) - 1);
3122 *dwSize = (DWORD)strlen(pname);
3126 krb5_free_unparsed_name(context, pname);
3129 krb5_free_principal(context, princ);
3132 krb5_cc_close(context, mslsa_ccache);
3135 krb5_free_context(context);
3140 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3142 // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3143 PSID pSystemSID = NULL;
3144 DWORD SystemSIDlength = 0, UserSIDlength = 0;
3145 PACL ccacheACL = NULL;
3146 DWORD ccacheACLlength = 0;
3147 PTOKEN_USER pTokenUser = NULL;
3156 /* Get System SID */
3157 if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3163 SystemSIDlength = GetLengthSid(pSystemSID);
3164 ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3165 + SystemSIDlength - sizeof(DWORD);
3168 if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3170 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3171 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3173 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3178 UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3180 ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
3185 ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3190 InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3191 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3192 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3195 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3196 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3197 pTokenUser->User.Sid);
3198 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3199 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3204 gle = GetLastError();
3205 if (gle != ERROR_NO_TOKEN)
3208 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3209 OWNER_SECURITY_INFORMATION,
3210 pTokenUser->User.Sid,
3214 gle = GetLastError();
3215 if (gle != ERROR_NO_TOKEN)
3219 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3220 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3225 gle = GetLastError();
3226 if (gle != ERROR_NO_TOKEN)
3233 LocalFree(pSystemSID);
3235 LocalFree(pTokenUser);
3237 LocalFree(ccacheACL);
3242 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3245 DWORD dwSize = size-1; /* leave room for nul */
3248 if (!hUserToken || !newfilename || size <= 0)
3251 *newfilename = '\0';
3253 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3254 if ( !dwLen || dwLen > dwSize )
3255 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3256 if ( !dwLen || dwLen > dwSize )
3259 newfilename[dwSize] = '\0';
3264 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3266 char filename[MAX_PATH] = "";
3268 char cachename[MAX_PATH + 8] = "FILE:";
3269 krb5_context context = NULL;
3270 krb5_error_code code;
3271 krb5_principal princ = NULL;
3272 krb5_ccache cc = NULL;
3273 krb5_ccache ncc = NULL;
3275 if (!user || !szLogonId)
3278 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3279 if ( count > sizeof(filename) || count == 0 ) {
3280 GetWindowsDirectory(filename, sizeof(filename));
3283 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3286 StringCbCat( filename, sizeof(filename), "\\");
3287 StringCbCat( filename, sizeof(filename), szLogonId);
3289 StringCbCat( cachename, sizeof(cachename), filename);
3291 DeleteFile(filename);
3293 code = krb5_init_context(&context);
3294 if (code) goto cleanup;
3296 code = krb5_parse_name(context, user, &princ);
3297 if (code) goto cleanup;
3299 code = KFW_get_ccache(context, princ, &cc);
3300 if (code) goto cleanup;
3302 code = krb5_cc_resolve(context, cachename, &ncc);
3303 if (code) goto cleanup;
3305 code = krb5_cc_initialize(context, ncc, princ);
3306 if (code) goto cleanup;
3308 code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3309 if (code) goto cleanup;
3311 code = krb5_cc_copy_creds(context,cc,ncc);
3315 krb5_cc_close(context, cc);
3319 krb5_cc_close(context, ncc);
3323 krb5_free_principal(context, princ);
3328 krb5_free_context(context);
3332 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3334 char cachename[MAX_PATH + 8] = "FILE:";
3335 krb5_context context = NULL;
3336 krb5_error_code code;
3337 krb5_principal princ = NULL;
3338 krb5_ccache cc = NULL;
3339 krb5_ccache ncc = NULL;
3345 if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3348 code = krb5_init_context(&context);
3351 StringCbCat( cachename, sizeof(cachename), filename);
3353 code = krb5_cc_resolve(context, cachename, &cc);
3354 if (code) goto cleanup;
3356 code = krb5_cc_get_principal(context, cc, &princ);
3358 code = krb5_cc_default(context, &ncc);
3360 code = krb5_cc_initialize(context, ncc, princ);
3363 code = krb5_cc_copy_creds(context,cc,ncc);
3366 krb5_cc_close(context, ncc);
3370 retval=0; /* success */
3374 krb5_cc_close(context, cc);
3378 DeleteFile(filename);
3381 krb5_free_principal(context, princ);
3386 krb5_free_context(context);
3392 KFW_get_default_realm(void)
3394 krb5_context ctx = NULL;
3395 char * def_realm = NULL, *realm = NULL;
3396 krb5_error_code code;
3398 code = krb5_init_context(&ctx);
3402 if (code = krb5_get_default_realm(ctx, &def_realm))
3405 realm = strdup(def_realm);
3409 krb5_free_default_realm(ctx, def_realm);
3412 krb5_free_context(ctx);
3417 /* We are including this
3419 /* Ticket lifetime. This defines the table used to lookup lifetime for the
3420 fixed part of rande of the one byte lifetime field. Values less than 0x80
3421 are intrpreted as the number of 5 minute intervals. Values from 0x80 to
3422 0xBF should be looked up in this table. The value of 0x80 is the same using
3423 both methods: 10 and two-thirds hours . The lifetime of 0xBF is 30 days.
3424 The intervening values of have a fixed ratio of roughly 1.06914. The value
3425 oxFF is defined to mean a ticket has no expiration time. This should be
3426 used advisedly since individual servers may impose defacto upperbounds on
3427 ticket lifetimes. */
3429 #define TKTLIFENUMFIXED 64
3430 #define TKTLIFEMINFIXED 0x80
3431 #define TKTLIFEMAXFIXED 0xBF
3432 #define TKTLIFENOEXPIRE 0xFF
3433 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
3435 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3436 38400, /* 10.67 hours, 0.44 days */
3437 41055, /* 11.40 hours, 0.48 days */
3438 43894, /* 12.19 hours, 0.51 days */
3439 46929, /* 13.04 hours, 0.54 days */
3440 50174, /* 13.94 hours, 0.58 days */
3441 53643, /* 14.90 hours, 0.62 days */
3442 57352, /* 15.93 hours, 0.66 days */
3443 61318, /* 17.03 hours, 0.71 days */
3444 65558, /* 18.21 hours, 0.76 days */
3445 70091, /* 19.47 hours, 0.81 days */
3446 74937, /* 20.82 hours, 0.87 days */
3447 80119, /* 22.26 hours, 0.93 days */
3448 85658, /* 23.79 hours, 0.99 days */
3449 91581, /* 25.44 hours, 1.06 days */
3450 97914, /* 27.20 hours, 1.13 days */
3451 104684, /* 29.08 hours, 1.21 days */
3452 111922, /* 31.09 hours, 1.30 days */
3453 119661, /* 33.24 hours, 1.38 days */
3454 127935, /* 35.54 hours, 1.48 days */
3455 136781, /* 37.99 hours, 1.58 days */
3456 146239, /* 40.62 hours, 1.69 days */
3457 156350, /* 43.43 hours, 1.81 days */
3458 167161, /* 46.43 hours, 1.93 days */
3459 178720, /* 49.64 hours, 2.07 days */
3460 191077, /* 53.08 hours, 2.21 days */
3461 204289, /* 56.75 hours, 2.36 days */
3462 218415, /* 60.67 hours, 2.53 days */
3463 233517, /* 64.87 hours, 2.70 days */
3464 249664, /* 69.35 hours, 2.89 days */
3465 266926, /* 74.15 hours, 3.09 days */
3466 285383, /* 79.27 hours, 3.30 days */
3467 305116, /* 84.75 hours, 3.53 days */
3468 326213, /* 90.61 hours, 3.78 days */
3469 348769, /* 96.88 hours, 4.04 days */
3470 372885, /* 103.58 hours, 4.32 days */
3471 398668, /* 110.74 hours, 4.61 days */
3472 426234, /* 118.40 hours, 4.93 days */
3473 455705, /* 126.58 hours, 5.27 days */
3474 487215, /* 135.34 hours, 5.64 days */
3475 520904, /* 144.70 hours, 6.03 days */
3476 556921, /* 154.70 hours, 6.45 days */
3477 595430, /* 165.40 hours, 6.89 days */
3478 636601, /* 176.83 hours, 7.37 days */
3479 680618, /* 189.06 hours, 7.88 days */
3480 727680, /* 202.13 hours, 8.42 days */
3481 777995, /* 216.11 hours, 9.00 days */
3482 831789, /* 231.05 hours, 9.63 days */
3483 889303, /* 247.03 hours, 10.29 days */
3484 950794, /* 264.11 hours, 11.00 days */
3485 1016537, /* 282.37 hours, 11.77 days */
3486 1086825, /* 301.90 hours, 12.58 days */
3487 1161973, /* 322.77 hours, 13.45 days */
3488 1242318, /* 345.09 hours, 14.38 days */
3489 1328218, /* 368.95 hours, 15.37 days */
3490 1420057, /* 394.46 hours, 16.44 days */
3491 1518247, /* 421.74 hours, 17.57 days */
3492 1623226, /* 450.90 hours, 18.79 days */
3493 1735464, /* 482.07 hours, 20.09 days */
3494 1855462, /* 515.41 hours, 21.48 days */
3495 1983758, /* 551.04 hours, 22.96 days */
3496 2120925, /* 589.15 hours, 24.55 days */
3497 2267576, /* 629.88 hours, 26.25 days */
3498 2424367, /* 673.44 hours, 28.06 days */
3500 }; /* 720.00 hours, 30.00 days */
3502 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3503 * returns the corresponding end time. There are four simple cases to be
3504 * handled. The first is a life of 0xff, meaning no expiration, and results in
3505 * an end time of 0xffffffff. The second is when life is less than the values
3506 * covered by the table. In this case, the end time is the start time plus the
3507 * number of 5 minute intervals specified by life. The third case returns
3508 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
3509 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3510 * table to extract the lifetime in seconds, which is added to start to produce
3514 life_to_time(afs_uint32 start, unsigned char life)
3518 if (life == TKTLIFENOEXPIRE)
3520 if (life < TKTLIFEMINFIXED)
3521 return start + life * 5 * 60;
3522 if (life > TKTLIFEMAXFIXED)
3523 return start + MAXTKTLIFETIME;
3524 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3525 return start + realLife;
3528 /* time_to_life - takes start and end times for the ticket and returns a
3529 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3530 * lifetimes above 127*5minutes. First, the special case of (end ==
3531 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
3532 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
3533 * less than the first table entry are handled by rounding the requested
3534 * lifetime *up* to the next 5 minute interval. The final step is to search
3535 * the table for the smallest entry *greater than or equal* to the requested
3536 * entry. The actual code is prepared to handle the case where the table is
3537 * unordered but that it an unnecessary frill. */
3539 static unsigned char
3540 time_to_life(afs_uint32 start, afs_uint32 end)
3542 int lifetime = end - start;
3546 if (end == NEVERDATE)
3547 return TKTLIFENOEXPIRE;
3548 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
3550 if (lifetime < tkt_lifetimes[0])
3551 return (lifetime + 5 * 60 - 1) / (5 * 60);
3553 best = MAXKTCTICKETLIFETIME;
3554 for (i = 0; i < TKTLIFENUMFIXED; i++)
3555 if (tkt_lifetimes[i] >= lifetime) {
3556 int diff = tkt_lifetimes[i] - lifetime;
3564 return best_i + TKTLIFEMINFIXED;
3567 DWORD KFW_get_default_mslsa_import(krb5_context context)
3569 static const char * lsh_settings_key = "";
3570 static const char * lsh_mslsa_value = "";
3576 rc = RegOpenKeyEx(HKEY_CURRENT_USER, lsh_settings_key, 0, KEY_QUERY_VALUE, &hKey);
3580 dwCount = sizeof(DWORD);
3581 rc = RegQueryValueEx(hKey, lsh_mslsa_value, 0, 0, (LPBYTE) &import, &dwCount);
3587 rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lsh_settings_key, 0, KEY_QUERY_VALUE, &hKey);
3591 dwCount = sizeof(DWORD);
3592 rc = RegQueryValueEx(hKey, lsh_mslsa_value, 0, 0, (LPBYTE) &import, &dwCount);
3598 DWORD KFW_get_default_lifetime(krb5_context context, const char * realm)
3600 static const char * lifetime_val_name = "ticket_lifetime";
3603 krb5_appdefault_time(context, "aklog", realm, lifetime_val_name, 0, &t);
3606 t = krb5_config_get_time_default(context, NULL, 0,
3607 "realms", realm, lifetime_val_name, NULL);
3610 t = krb5_config_get_time_default(context, NULL, 0,
3611 "libdefaults", lifetime_val_name, NULL);