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>
67 #include <afs/ptserver.h>
68 #include <afs/ptuser.h>
70 #include <afs/com_err.h>
72 #include <WINNT\afsreg.h>
76 #include "afskfw-int.h"
83 #include <krbcompat_delayload.h>
85 #ifndef KRB5_TC_OPENCLOSE
86 #define KRB5_TC_OPENCLOSE 0x00000001
90 * TIMING _____________________________________________________________________
94 #define cminREMIND_TEST 1 // test every minute for expired creds
95 #define cminREMIND_WARN 15 // warn if creds expire in 15 minutes
96 #define cminRENEW 20 // renew creds when there are 20 minutes remaining
97 #define cminMINLIFE 30 // minimum life of Kerberos creds
99 #define c100ns1SECOND (LONGLONG)10000000
100 #define cmsec1SECOND 1000
101 #define cmsec1MINUTE 60000
102 #define csec1MINUTE 60
104 /* Static Prototypes */
105 char *afs_realm_of_cell(krb5_context, struct afsconf_cell *);
106 static long get_cellconfig_callback(void *, struct sockaddr_in *, char *, unsigned short);
107 int KFW_AFS_get_cellconfig(char *, struct afsconf_cell *, char *);
108 static krb5_error_code KRB5_CALLCONV KRB5_prompter( krb5_context context,
109 void *data, const char *name, const char *banner, int num_prompts,
110 krb5_prompt prompts[]);
112 /* Static Declarations */
113 static int inited = 0;
114 static int mid_cnt = 0;
115 static struct textField * mid_tb = NULL;
116 static struct principal_ccache_data * princ_cc_data = NULL;
117 static struct cell_principal_map * cell_princ_map = NULL;
120 #define DEFAULT_LIFETIME pLeash_get_default_lifetime()
122 #define DEFAULT_LIFETIME (24 * 60)
126 DebugPrintf(const char * fmt, ...)
128 if (IsDebuggerPresent()) {
133 StringCbVPrintfA(buf, sizeof(buf), fmt, vl);
134 OutputDebugStringA(buf);
142 static int inited = 0;
145 char mutexName[MAX_PATH];
146 HANDLE hMutex = NULL;
148 StringCbPrintf( mutexName, sizeof(mutexName), "AFS KFW Init pid=%d", getpid());
150 hMutex = CreateMutex( NULL, TRUE, mutexName );
151 if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
152 if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
161 if ( KFW_is_available() ) {
162 char rootcell[CELL_MAXNAMELEN+1];
164 KFW_import_windows_lsa();
165 #endif /* USE_MS2MIT */
166 KFW_import_ccache_data();
167 KFW_AFS_renew_expiring_tokens();
169 /* WIN32 NOTE: no way to get max chars */
170 if (!cm_GetRootCellName(rootcell))
171 KFW_AFS_renew_token_for_cell(rootcell);
174 ReleaseMutex(hMutex);
177 initialize_KTC_error_table();
178 initialize_PT_error_table();
187 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
190 static int init = TRUE;
191 static int bIsWow64 = FALSE;
195 LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
197 hModule = GetModuleHandle(TEXT("kernel32"));
199 fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process");
201 if (NULL != fnIsWow64Process)
203 if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
205 // on error, assume FALSE.
206 // in other words, do nothing.
209 FreeLibrary(hModule);
217 KFW_accept_dotted_usernames(void)
223 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
224 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
225 if (code == ERROR_SUCCESS) {
227 code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
228 (BYTE *) &value, &len);
229 RegCloseKey(parmKey);
231 if (code != ERROR_SUCCESS) {
232 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
233 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
234 if (code == ERROR_SUCCESS) {
236 code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
237 (BYTE *) &value, &len);
238 RegCloseKey (parmKey);
252 KFW_is_available(void)
258 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
259 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
260 if (code == ERROR_SUCCESS) {
261 len = sizeof(enableKFW);
262 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
263 (BYTE *) &enableKFW, &len);
264 RegCloseKey (parmKey);
267 if (code != ERROR_SUCCESS) {
268 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
269 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
270 if (code == ERROR_SUCCESS) {
271 len = sizeof(enableKFW);
272 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
273 (BYTE *) &enableKFW, &len);
274 RegCloseKey (parmKey);
283 /* If this is non-zero, then some Kerberos library was loaded. */
284 return (krb5_init_context != NULL);
288 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
289 int FreeContextFlag, krb5_context * context,
294 int krb5Error = ((int)(rc & 255));
296 errText = krb5_get_error_message(*context, rc);
297 StringCbPrintf(message, sizeof(message),
298 "%s\n(Kerberos error %ld)\n\n%s failed",
302 krb5_free_error_message(*context, (char *)errText);
304 DebugPrintf("%s", message);
306 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
310 if (FreeContextFlag == 1) {
312 if (context && *context != NULL) {
314 if (cache && *cache != NULL) {
315 krb5_cc_close(*context, *cache);
319 krb5_free_context(*context);
328 KFW_AFS_update_princ_ccache_data(krb5_context context, krb5_ccache cc, int lsa)
330 struct principal_ccache_data * next = princ_cc_data;
331 krb5_principal principal = 0;
333 const char * ccname = NULL;
334 const char * cctype = NULL;
335 char * ccfullname = NULL;
336 krb5_error_code code = 0;
337 krb5_error_code cc_code = 0;
344 if (context == 0 || cc == 0)
347 code = krb5_cc_get_principal(context, cc, &principal);
350 code = krb5_unparse_name(context, principal, &pname);
351 if ( code ) goto cleanup;
353 ccname = krb5_cc_get_name(context, cc);
354 if (!ccname) goto cleanup;
356 cctype = krb5_cc_get_type(context, cc);
357 if (!cctype) goto cleanup;
359 len = strlen(ccname) + strlen(cctype) + 2;
360 ccfullname = malloc(len);
361 if (!ccfullname) goto cleanup;
363 StringCbPrintf(ccfullname, len, "%s:%s", cctype, ccname);
365 // Search the existing list to see if we have a match
367 for ( ; next ; next = next->next ) {
368 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccfullname) )
373 // If not, match add a new node to the beginning of the list and assign init it
375 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
376 next->next = princ_cc_data;
377 princ_cc_data = next;
378 next->principal = _strdup(pname);
379 next->ccache_name = ccfullname;
381 next->from_lsa = lsa;
383 next->expiration_time = 0;
387 flags = 0; // turn off OPENCLOSE mode
388 code = krb5_cc_set_flags(context, cc, flags);
389 if ( code ) goto cleanup;
391 code = krb5_timeofday(context, &now);
393 cc_code = krb5_cc_start_seq_get(context, cc, &cur);
395 while (!(cc_code = krb5_cc_next_cred(context, cc, &cur, &creds))) {
396 if ( creds.flags.b.initial) {
398 // we found the ticket we are looking for
399 // check validity of timestamp
400 // We add a 5 minutes fudge factor to compensate for potential
401 // clock skew errors between the KDC and client OS
403 valid = ((creds.times.starttime > 0) &&
404 now >= (creds.times.starttime - 300) &&
405 now < (creds.times.endtime + 300) &&
406 !creds.flags.b.invalid);
408 if ( next->from_lsa) {
410 next->expiration_time = creds.times.endtime;
412 } else if ( valid ) {
414 next->expiration_time = creds.times.endtime;
415 next->renew = (creds.times.renew_till > creds.times.endtime) &&
416 creds.flags.b.renewable;
419 next->expiration_time = 0;
423 krb5_free_cred_contents(context, &creds);
424 cc_code = KRB5_CC_END;
427 krb5_free_cred_contents(context, &creds);
430 if (cc_code == KRB5_CC_END) {
431 code = krb5_cc_end_seq_get(context, cc, &cur);
432 if (code) goto cleanup;
436 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
437 code = krb5_cc_set_flags(context, cc, flags);
442 krb5_free_unparsed_name(context,pname);
444 krb5_free_principal(context,principal);
448 KFW_AFS_find_ccache_for_principal(krb5_context context, char * principal,
449 char **ccache, int valid_only)
451 struct principal_ccache_data * next = princ_cc_data;
452 char * response = NULL;
454 if ( !principal || !ccache )
458 if ( (!valid_only || !next->expired) && !strcmp(next->principal, principal) ) {
460 // we always want to prefer the MS Kerberos LSA cache or
461 // the cache afscreds created specifically for the principal
462 // if the current entry is either one, drop the previous find
463 if ( next->from_lsa || !strcmp(next->ccache_name, principal) )
466 response = _strdup(next->ccache_name);
467 // MS Kerberos LSA is our best option so use it and quit
468 if ( next->from_lsa )
482 KFW_AFS_delete_princ_ccache_data(krb5_context context, char * pname, char * ccname)
484 struct principal_ccache_data ** next = &princ_cc_data;
486 if ( !pname && !ccname )
490 if ( !strcmp((*next)->principal,pname) ||
491 !strcmp((*next)->ccache_name,ccname) ) {
493 free((*next)->principal);
494 free((*next)->ccache_name);
496 (*next) = (*next)->next;
503 KFW_AFS_update_cell_princ_map(krb5_context context, char * cell, char *pname, int active)
505 struct cell_principal_map * next = cell_princ_map;
507 // Search the existing list to see if we have a match
509 for ( ; next ; next = next->next ) {
510 if ( !strcmp(next->cell, cell) ) {
511 if ( !strcmp(next->principal,pname) ) {
512 next->active = active;
515 // OpenAFS currently has a restriction of one active token per cell
516 // Therefore, whenever we update the table with a new active cell we
517 // must mark all of the other principal to cell entries as inactive.
525 // If not, match add a new node to the beginning of the list and assign init it
527 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
528 next->next = cell_princ_map;
529 cell_princ_map = next;
530 next->principal = _strdup(pname);
531 next->cell = _strdup(cell);
532 next->active = active;
537 KFW_AFS_delete_cell_princ_maps(krb5_context context, char * pname, char * cell)
539 struct cell_principal_map ** next = &cell_princ_map;
541 if ( !pname && !cell )
545 if ( !strcmp((*next)->principal,pname) ||
546 !strcmp((*next)->cell,cell) ) {
548 free((*next)->principal);
551 (*next) = (*next)->next;
557 // Returns (if possible) a principal which has been known in
558 // the past to have been used to obtain tokens for the specified
560 // TODO: Attempt to return one which has not yet expired by checking
561 // the principal/ccache data
563 KFW_AFS_find_principals_for_cell(krb5_context context, char * cell, char **principals[], int active_only)
565 struct cell_principal_map * next_map = cell_princ_map;
566 const char * princ = NULL;
573 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
576 next_map = next_map->next;
579 if ( !principals || !count )
582 *principals = (char **) malloc(sizeof(char *) * count);
583 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
585 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
586 (*principals)[i++] = _strdup(next_map->principal);
593 KFW_AFS_find_cells_for_princ(krb5_context context, char * pname, char **cells[], int active_only)
596 struct cell_principal_map * next_map = cell_princ_map;
597 const char * princ = NULL;
603 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
606 next_map = next_map->next;
612 *cells = (char **) malloc(sizeof(char *) * count);
613 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
615 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
616 (*cells)[i++] = _strdup(next_map->cell);
623 escape_unsafe_principal_characters(const char * pname,
631 for (src = pname; *src != '\0'; ++len, ++src) {
632 if (*src == '\\' || *src == '#' || *src == '<' ||
633 *src == '>' || *src == ':' || *src == '"' ||
634 *src == '/' || *src == '|' || *src == '?' ||
641 *new_name = (char *) malloc(len);
643 if (*new_name == NULL)
646 for (src = pname, dest = *new_name; *src != '\0'; ++src) {
648 case '\\': *dest++ = '#'; *dest++ = 'b'; break;
650 case '#' : *dest++ = '#'; *dest++ = '#'; break;
652 case '<' : *dest++ = '#'; *dest++ = 'l'; break;
654 case '>' : *dest++ = '#'; *dest++ = 'g'; break;
656 case ':' : *dest++ = '#'; *dest++ = 'c'; break;
658 case '"' : *dest++ = '#'; *dest++ = 't'; break;
660 case '/' : *dest++ = '#'; *dest++ = 'f'; break;
662 case '|' : *dest++ = '#'; *dest++ = 'p'; break;
664 case '?' : *dest++ = '#'; *dest++ = 'q'; break;
666 case '*' : *dest++ = '#'; *dest++ = 'a'; break;
668 default: *dest++ = *src;
676 get_default_ccache_name_for_principal(krb5_context context, krb5_principal principal,
680 char * epname = NULL;
681 krb5_error_code code;
683 char temppath[MAX_PATH]="";
687 code = krb5_unparse_name(context, principal, &pname);
688 if (code) goto cleanup;
690 escape_unsafe_principal_characters(pname, &epname);
692 len = strlen(epname);
694 *cc_name = (char *) malloc(len);
696 GetTempPathA(MAX_PATH, temppath);
697 StringCbPrintfA(*cc_name, len, "FILE:%skrb5cc_%s", temppath, epname);
701 krb5_free_unparsed_name(context, pname);
710 is_default_ccache_for_principal(krb5_context context, krb5_principal principal,
713 const char * cc_name;
714 char * def_cc_name = NULL;
716 const char *bs_def_cc;
719 cc_name = krb5_cc_get_name(context, cc);
721 get_default_ccache_name_for_principal(context, principal, &def_cc_name);
723 is_default = (cc_name != NULL && def_cc_name != NULL &&
725 (bs_cc = strrchr(cc_name, '\\')) != NULL &&
727 (bs_def_cc = strrchr(def_cc_name, '\\')) != NULL &&
729 !strcmp(bs_cc, bs_def_cc));
737 /** Given a principal return an existing ccache or create one and return */
739 KFW_get_ccache(krb5_context alt_context, krb5_principal principal, krb5_ccache * cc)
741 krb5_context context = NULL;
743 char * ccname = NULL;
744 krb5_error_code code;
747 context = alt_context;
749 code = krb5_init_context(&context);
750 if (code) goto cleanup;
754 code = krb5_unparse_name(context, principal, &pname);
755 if (code) goto cleanup;
757 if ( !KFW_AFS_find_ccache_for_principal(context,pname,&ccname,TRUE) &&
758 !KFW_AFS_find_ccache_for_principal(context,pname,&ccname,FALSE)) {
760 get_default_ccache_name_for_principal(context, principal, &ccname);
762 code = krb5_cc_resolve(context, ccname, cc);
764 code = krb5_cc_default(context, cc);
765 if (code) goto cleanup;
772 krb5_free_unparsed_name(context,pname);
773 if (context && (context != alt_context))
774 krb5_free_context(context);
780 // Import Microsoft Credentials into a new MIT ccache
782 KFW_import_windows_lsa(void)
784 krb5_context context = NULL;
785 krb5_ccache cc = NULL;
786 krb5_principal princ = NULL;
788 const char * princ_realm;
789 krb5_error_code code;
790 char cell[128]="", realm[128]="", *def_realm = 0;
791 DWORD dwMsLsaImport = 1;
793 code = krb5_init_context(&context);
794 if (code) goto cleanup;
796 code = krb5_cc_resolve(context, LSA_CCNAME, &cc);
797 if (code) goto cleanup;
799 KFW_AFS_update_princ_ccache_data(context, cc, TRUE);
801 code = krb5_cc_get_principal(context, cc, &princ);
802 if ( code ) goto cleanup;
804 dwMsLsaImport = KFW_get_default_mslsa_import(context);
805 switch ( dwMsLsaImport ) {
806 case 0: /* do not import */
808 case 1: /* always import */
810 case 2: { /* matching realm */
811 const char *ms_realm;
813 ms_realm = krb5_principal_get_realm(context, princ);
815 if (code = krb5_get_default_realm(context, &def_realm))
818 if (strcmp(def_realm, ms_realm))
826 code = krb5_unparse_name(context,princ,&pname);
827 if ( code ) goto cleanup;
829 princ_realm = krb5_principal_get_realm(context, princ);
830 StringCchCopyA(realm, sizeof(realm), princ_realm);
831 StringCchCopyA(cell, sizeof(cell), princ_realm);
834 code = KFW_AFS_klog(context, cc, "afs", cell, realm,
835 KFW_get_default_lifetime(context, realm), NULL);
837 DebugPrintf("KFW_AFS_klog() returns: %d\n", code);
839 if ( code ) goto cleanup;
841 KFW_AFS_update_cell_princ_map(context, cell, pname, TRUE);
845 krb5_free_unparsed_name(context,pname);
847 krb5_free_principal(context,princ);
849 krb5_free_default_realm(context, def_realm);
851 krb5_cc_close(context,cc);
853 krb5_free_context(context);
855 #endif /* USE_MS2MIT */
858 get_canonical_ccache(krb5_context context, krb5_ccache * pcc)
860 krb5_error_code code;
861 krb5_ccache cc = *pcc;
862 krb5_principal principal = 0;
864 code = krb5_cc_get_principal(context, cc, &principal);
868 if ( !is_default_ccache_for_principal(context, principal, cc)
869 && strcmp(krb5_cc_get_type(context, cc), LSA_CCTYPE) != 0) {
871 char * def_cc_name = NULL;
872 krb5_ccache def_cc = 0;
873 krb5_principal def_cc_princ = 0;
876 get_default_ccache_name_for_principal(context, principal, &def_cc_name);
878 code = krb5_cc_resolve(context, def_cc_name, &def_cc);
881 code = krb5_cc_get_principal(context, def_cc, &def_cc_princ);
882 if (code || !krb5_principal_compare(context, def_cc_princ, principal)) {
883 /* def_cc either doesn't exist or is home to an
886 DebugPrintf("Copying ccache [%s:%s]->[%s:%s]",
887 krb5_cc_get_type(context, cc), krb5_cc_get_name(context, cc),
888 krb5_cc_get_type(context, def_cc),
889 krb5_cc_get_name(context, def_cc));
891 code = krb5_cc_initialize(context, def_cc, principal);
894 code = krb5_cc_copy_creds(context, cc, def_cc);
896 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
900 code = krb5_cc_close(context, cc);
908 krb5_cc_close(context, def_cc);
911 krb5_free_principal(context, def_cc_princ);
918 krb5_free_principal(context, principal);
920 if (code == 0 && cc != 0) {
929 static krb5_error_code
930 check_and_get_tokens_for_ccache(krb5_context context, krb5_ccache cc)
932 krb5_error_code code = 0;
933 krb5_error_code cc_code = 0;
936 char * principal_name = NULL;
939 krb5_principal principal = 0;
940 code = krb5_cc_get_principal(context, cc, &principal);
943 code = krb5_unparse_name(context, principal, &principal_name);
946 krb5_free_principal(context, principal);
951 krb5_free_unparsed_name(context, principal_name);
955 cc_code = krb5_cc_start_seq_get(context, cc, &cur);
957 while (!(cc_code = krb5_cc_next_cred(context, cc, &cur, &creds))) {
959 const char * sname = krb5_principal_get_comp_string(context, creds.server, 0);
960 const char * cell = krb5_principal_get_comp_string(context, creds.server, 1);
961 const char * realm = krb5_principal_get_realm(context, creds.server);
963 if ( sname && cell && !strcmp("afs",sname) ) {
965 struct ktc_principal aserver;
966 struct ktc_principal aclient;
967 struct ktc_token atoken;
970 DebugPrintf("Found AFS ticket: %s%s%s@%s\n",
971 sname, (cell ? "/":""), (cell? cell : ""), realm);
973 memset(&aserver, '\0', sizeof(aserver));
974 StringCbCopy(aserver.name, sizeof(aserver.name), sname);
975 StringCbCopy(aserver.cell, sizeof(aserver.cell), cell);
977 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
979 // Found a token in AFS Client Server which matches
981 char pname[128], *p, *q;
983 for ( p=pname, q=aclient.name; *q; p++, q++)
986 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
991 DebugPrintf("Found AFS token: %s\n", pname);
993 if (strcmp(pname, principal_name) != 0)
996 KFW_AFS_update_cell_princ_map(context, cell, principal_name, active);
999 // Attempt to import it
1001 KFW_AFS_update_cell_princ_map(context, cell, principal_name, active);
1003 DebugPrintf("Calling KFW_AFS_klog() to obtain token\n");
1005 code = KFW_AFS_klog(context, cc, "afs", cell, realm,
1006 KFW_get_default_lifetime(context, realm), NULL);
1008 DebugPrintf("KFW_AFS_klog() returns: %d\n", code);
1013 DebugPrintf("Found ticket: %s%s%s@%s\n", sname,
1014 (cell? "/":""), (cell? cell:""), realm);
1017 krb5_free_cred_contents(context, &creds);
1020 if (cc_code == KRB5_CC_END) {
1021 cc_code = krb5_cc_end_seq_get(context, cc, &cur);
1027 // If there are existing MIT credentials, copy them to a new
1028 // ccache named after the principal
1030 // Enumerate all existing MIT ccaches and construct entries
1031 // in the principal_ccache table
1033 // Enumerate all existing AFS Tokens and construct entries
1034 // in the cell_principal table
1036 KFW_import_ccache_data(void)
1038 krb5_context context = NULL;
1040 krb5_error_code code;
1041 krb5_cccol_cursor cccol_cur;
1044 if ( IsDebuggerPresent() )
1045 OutputDebugString("KFW_import_ccache_data()\n");
1047 code = krb5_init_context(&context);
1048 if (code) goto cleanup;
1050 code = krb5_cccol_cursor_new(context, &cccol_cur);
1051 if (code) goto cleanup;
1053 while ((code = krb5_cccol_cursor_next(context, cccol_cur, &cc)) == 0 && cc != NULL) {
1055 if (!get_canonical_ccache(context, &cc)) {
1057 krb5_cc_close(context, cc);
1061 /* Turn off OPENCLOSE mode */
1062 code = krb5_cc_set_flags(context, cc, 0);
1063 if ( code ) goto cleanup;
1065 KFW_AFS_update_princ_ccache_data(context, cc,
1066 !strcmp(krb5_cc_get_type(context, cc),
1069 check_and_get_tokens_for_ccache(context, cc);
1071 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1072 code = krb5_cc_set_flags(context, cc, flags);
1075 krb5_cc_close(context,cc);
1080 krb5_cccol_cursor_free(context, &cccol_cur);
1084 krb5_free_context(context);
1089 KFW_AFS_get_cred( char * username,
1096 static char reason[1024]="";
1097 krb5_context context = NULL;
1098 krb5_ccache cc = NULL;
1099 char * realm = NULL, * userrealm = NULL;
1100 krb5_principal principal = NULL;
1101 char * pname = NULL;
1102 krb5_error_code code;
1103 char local_cell[CELL_MAXNAMELEN+1];
1104 char **cells = NULL;
1106 struct afsconf_cell cellconfig;
1109 DebugPrintf("KFW_AFS_get_cred for token %s in cell %s\n", username, cell);
1111 memset(&cellconfig, 0, sizeof(cellconfig));
1113 code = krb5_init_context(&context);
1114 if ( code ) goto cleanup;
1116 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1117 if ( code ) goto cleanup;
1119 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1121 userrealm = strchr(username,'@');
1123 pname = strdup(username);
1124 if (!KFW_accept_dotted_usernames()) {
1125 userrealm = strchr(pname, '@');
1128 /* handle kerberos iv notation */
1129 while ( dot = strchr(pname,'.') ) {
1136 size_t len = strlen(username) + strlen(realm) + 2;
1137 pname = malloc(len);
1138 if (pname == NULL) {
1139 code = KRB5KRB_ERR_GENERIC;
1142 StringCbCopy(pname, len, username);
1144 if (!KFW_accept_dotted_usernames()) {
1145 /* handle kerberos iv notation */
1146 while ( dot = strchr(pname,'.') ) {
1150 StringCbCat( pname, len, "@");
1151 StringCbCat( pname, len, realm);
1153 if ( IsDebuggerPresent() ) {
1154 OutputDebugString("Realm of Cell: ");
1155 OutputDebugString(realm);
1156 OutputDebugString("\n");
1157 OutputDebugString("Realm of User: ");
1158 OutputDebugString(userrealm?userrealm:"<NULL>");
1159 OutputDebugString("\n");
1162 code = krb5_parse_name(context, pname, &principal);
1163 if ( code ) goto cleanup;
1165 code = KFW_get_ccache(context, principal, &cc);
1166 if ( code ) goto cleanup;
1168 if ( lifetime == 0 )
1169 lifetime = KFW_get_default_lifetime(context, realm);
1171 if ( password && password[0] ) {
1172 code = KFW_kinit( context, cc, HWND_DESKTOP,
1177 0, /* forwardable */
1178 0, /* not proxiable */
1180 1, /* noaddresses */
1181 0 /* no public ip */
1183 pLeash_get_default_forwardable(),
1184 pLeash_get_default_proxiable(),
1185 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1186 pLeash_get_default_noaddresses(),
1187 pLeash_get_default_publicip()
1188 #endif /* USE_LEASH */
1191 if ( IsDebuggerPresent() ) {
1193 StringCbPrintf(message, sizeof(message), "KFW_kinit() returns: %d\n", code);
1194 OutputDebugString(message);
1196 if ( code ) goto cleanup;
1198 KFW_AFS_update_princ_ccache_data(context, cc, FALSE);
1201 code = KFW_AFS_klog(context, cc, "afs", cell, realm, lifetime, smbname);
1202 if ( IsDebuggerPresent() ) {
1204 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1205 OutputDebugString(message);
1207 if ( code ) goto cleanup;
1209 KFW_AFS_update_cell_princ_map(context, cell, pname, TRUE);
1211 // Attempt to obtain new tokens for other cells supported by the same
1213 cell_count = KFW_AFS_find_cells_for_princ(context, pname, &cells, TRUE);
1214 if ( cell_count > 1 ) {
1215 while ( cell_count-- ) {
1216 if ( strcmp(cells[cell_count],cell) ) {
1217 if ( IsDebuggerPresent() ) {
1219 StringCbPrintf(message, sizeof(message),
1220 "found another cell for the same principal: %s\n", cell);
1221 OutputDebugString(message);
1224 if (cellconfig.linkedCell) {
1225 free(cellconfig.linkedCell);
1226 cellconfig.linkedCell = NULL;
1228 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1229 if ( code ) continue;
1231 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1232 if ( IsDebuggerPresent() ) {
1233 OutputDebugString("Realm: ");
1234 OutputDebugString(realm);
1235 OutputDebugString("\n");
1238 code = KFW_AFS_klog(context, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1239 if ( IsDebuggerPresent() ) {
1241 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1242 OutputDebugString(message);
1245 free(cells[cell_count]);
1248 } else if ( cell_count == 1 ) {
1257 krb5_cc_close(context, cc);
1258 if ( cellconfig.linkedCell )
1259 free(cellconfig.linkedCell);
1261 if ( code && reasonP ) {
1262 const char *msg = krb5_get_error_message(context, code);
1263 StringCbCopyN( reason, sizeof(reason),
1264 msg, sizeof(reason) - 1);
1266 krb5_free_error_message(context, msg);
1272 KFW_AFS_destroy_tickets_for_cell(char * cell)
1274 krb5_context context = NULL;
1275 krb5_error_code code;
1277 char ** principals = NULL;
1279 DebugPrintf("KFW_AFS_destroy_tickets_for_cell: %s\n", cell);
1281 code = krb5_init_context(&context);
1282 if (code) context = 0;
1284 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, FALSE);
1286 krb5_principal princ = 0;
1290 int cell_count = KFW_AFS_find_cells_for_princ(context, principals[count], NULL, TRUE);
1291 if ( cell_count > 1 ) {
1292 // TODO - What we really should do here is verify whether or not any of the
1293 // other cells which use this principal to obtain its credentials actually
1294 // have valid tokens or not. If they are currently using these credentials
1295 // we will skip them. For the time being we assume that if there is an active
1296 // map in the table that they are actively being used.
1300 code = krb5_parse_name(context, principals[count], &princ);
1301 if (code) goto loop_cleanup;
1303 code = KFW_get_ccache(context, princ, &cc);
1304 if (code) goto loop_cleanup;
1306 code = krb5_cc_destroy(context, cc);
1311 krb5_cc_close(context, cc);
1315 krb5_free_principal(context, princ);
1319 KFW_AFS_update_cell_princ_map(context, cell, principals[count], FALSE);
1320 free(principals[count]);
1325 krb5_free_context(context);
1330 KFW_AFS_destroy_tickets_for_principal(char * user)
1332 krb5_context context = NULL;
1333 krb5_error_code code;
1335 char ** cells = NULL;
1336 krb5_principal princ = NULL;
1337 krb5_ccache cc = NULL;
1339 DebugPrintf("KFW_AFS_destroy_tickets_for_user: %s\n", user);
1341 code = krb5_init_context(&context);
1344 code = krb5_parse_name(context, user, &princ);
1345 if (code) goto loop_cleanup;
1347 code = KFW_get_ccache(context, princ, &cc);
1348 if (code) goto loop_cleanup;
1350 code = krb5_cc_destroy(context, cc);
1355 krb5_cc_close(context, cc);
1359 krb5_free_principal(context, princ);
1363 count = KFW_AFS_find_cells_for_princ(context, user, &cells, TRUE);
1366 KFW_AFS_update_cell_princ_map(context, cells[count], user, FALSE);
1373 krb5_free_context(context);
1379 KFW_AFS_renew_expiring_tokens(void)
1381 krb5_error_code code = 0;
1382 krb5_context context = NULL;
1383 krb5_ccache cc = NULL;
1385 struct principal_ccache_data * pcc_next = princ_cc_data;
1388 const char * realm = NULL;
1389 char local_cell[CELL_MAXNAMELEN+1]="";
1390 struct afsconf_cell cellconfig;
1392 if ( pcc_next == NULL ) // nothing to do
1395 if ( IsDebuggerPresent() ) {
1396 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1399 memset(&cellconfig, 0, sizeof(cellconfig));
1401 code = krb5_init_context(&context);
1402 if (code) goto cleanup;
1404 code = krb5_timeofday(context, &now);
1405 if (code) goto cleanup;
1407 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1408 if ( pcc_next->expired )
1411 if ( now >= (pcc_next->expiration_time) ) {
1412 if ( !pcc_next->from_lsa ) {
1413 pcc_next->expired = 1;
1418 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1419 code = krb5_cc_resolve(context, pcc_next->ccache_name, &cc);
1422 code = KFW_renew(context,cc);
1424 if ( code && pcc_next->from_lsa)
1426 #endif /* USE_MS2MIT */
1429 KFW_AFS_update_princ_ccache_data(context, cc, pcc_next->from_lsa);
1430 if (code) goto loop_cleanup;
1432 // Attempt to obtain new tokens for other cells supported by the same
1434 cell_count = KFW_AFS_find_cells_for_princ(context, pcc_next->principal, &cells, TRUE);
1435 if ( cell_count > 0 ) {
1436 while ( cell_count-- ) {
1437 if ( IsDebuggerPresent() ) {
1438 OutputDebugString("Cell: ");
1439 OutputDebugString(cells[cell_count]);
1440 OutputDebugString("\n");
1442 if (cellconfig.linkedCell) {
1443 free(cellconfig.linkedCell);
1444 cellconfig.linkedCell = NULL;
1446 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1447 if ( code ) continue;
1448 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1449 if ( IsDebuggerPresent() ) {
1450 OutputDebugString("Realm: ");
1451 OutputDebugString(realm);
1452 OutputDebugString("\n");
1454 code = KFW_AFS_klog(context, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1455 if ( IsDebuggerPresent() ) {
1457 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1458 OutputDebugString(message);
1460 free(cells[cell_count]);
1468 krb5_cc_close(context,cc);
1475 krb5_cc_close(context,cc);
1477 krb5_free_context(context);
1478 if (cellconfig.linkedCell)
1479 free(cellconfig.linkedCell);
1486 KFW_AFS_renew_token_for_cell(char * cell)
1488 krb5_error_code code = 0;
1489 krb5_context context = NULL;
1491 char ** principals = NULL;
1493 if ( IsDebuggerPresent() ) {
1494 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1495 OutputDebugString(cell);
1496 OutputDebugString("\n");
1499 code = krb5_init_context(&context);
1500 if (code) goto cleanup;
1502 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, TRUE);
1504 // We know we must have a credential somewhere since we are
1505 // trying to renew a token
1507 KFW_import_ccache_data();
1508 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, TRUE);
1511 krb5_principal princ = 0;
1512 krb5_principal service = 0;
1514 krb5_creds mcreds, creds;
1515 #endif /* COMMENT */
1517 const char * realm = NULL;
1518 struct afsconf_cell cellconfig;
1519 char local_cell[CELL_MAXNAMELEN+1];
1521 memset(&cellconfig, 0, sizeof(cellconfig));
1524 code = krb5_parse_name(context, principals[count], &princ);
1525 if (code) goto loop_cleanup;
1527 code = KFW_get_ccache(context, princ, &cc);
1528 if (code) goto loop_cleanup;
1530 if (cellconfig.linkedCell) {
1531 free(cellconfig.linkedCell);
1532 cellconfig.linkedCell = NULL;
1534 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1535 if ( code ) goto loop_cleanup;
1537 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1538 if ( IsDebuggerPresent() ) {
1539 OutputDebugString("Realm: ");
1540 OutputDebugString(realm);
1541 OutputDebugString("\n");
1545 /* krb5_cc_remove_cred() is not implemented
1548 code = krb5_build_principal(context, &service, strlen(realm),
1549 realm, "afs", cell, NULL);
1551 memset(&mcreds, 0, sizeof(krb5_creds));
1552 mcreds.client = princ;
1553 mcreds.server = service;
1555 code = krb5_cc_retrieve_cred(context, cc, 0, &mcreds, &creds);
1557 if ( IsDebuggerPresent() ) {
1558 char * cname, *sname;
1559 krb5_unparse_name(context, creds.client, &cname);
1560 krb5_unparse_name(context, creds.server, &sname);
1561 OutputDebugString("Removing credential for client \"");
1562 OutputDebugString(cname);
1563 OutputDebugString("\" and service \"");
1564 OutputDebugString(sname);
1565 OutputDebugString("\"\n");
1566 krb5_free_unparsed_name(context,cname);
1567 krb5_free_unparsed_name(context,sname);
1570 code = krb5_cc_remove_cred(context, cc, 0, &creds);
1571 krb5_free_principal(context, creds.client);
1572 krb5_free_principal(context, creds.server);
1575 #endif /* COMMENT */
1577 code = KFW_AFS_klog(context, cc, "afs", cell, (char *)realm, 0,NULL);
1578 if ( IsDebuggerPresent() ) {
1580 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1581 OutputDebugString(message);
1586 krb5_cc_close(context, cc);
1590 krb5_free_principal(context, princ);
1594 krb5_free_principal(context, service);
1597 if (cellconfig.linkedCell) {
1598 free(cellconfig.linkedCell);
1599 cellconfig.linkedCell = NULL;
1602 KFW_AFS_update_cell_princ_map(context, cell, principals[count], code ? FALSE : TRUE);
1603 free(principals[count]);
1607 code = -1; // we did not renew the tokens
1611 krb5_free_context(context);
1612 return (code ? FALSE : TRUE);
1617 KFW_AFS_renew_tokens_for_all_cells(void)
1619 struct cell_principal_map * next = cell_princ_map;
1621 DebugPrintf("KFW_AFS_renew_tokens_for_all()\n");
1626 for ( ; next ; next = next->next ) {
1628 KFW_AFS_renew_token_for_cell(next->cell);
1634 KFW_renew(krb5_context alt_context, krb5_ccache alt_cc)
1636 krb5_error_code code = 0;
1637 krb5_context context = NULL;
1638 krb5_ccache cc = NULL;
1639 krb5_principal me = NULL;
1640 krb5_principal server = NULL;
1641 krb5_creds my_creds;
1642 const char *realm = NULL;
1644 memset(&my_creds, 0, sizeof(krb5_creds));
1646 if ( alt_context ) {
1647 context = alt_context;
1649 code = krb5_init_context(&context);
1650 if (code) goto cleanup;
1656 code = krb5_cc_default(context, &cc);
1657 if (code) goto cleanup;
1660 code = krb5_cc_get_principal(context, cc, &me);
1661 if (code) goto cleanup;
1663 realm = krb5_principal_get_realm(context, me);
1665 code = krb5_make_principal(context, &server, realm,
1666 KRB5_TGS_NAME, realm, NULL);
1670 if ( IsDebuggerPresent() ) {
1671 char * cname, *sname;
1672 krb5_unparse_name(context, me, &cname);
1673 krb5_unparse_name(context, server, &sname);
1674 DebugPrintf("Renewing credential for client \"%s\" and service\"%s\"\n",
1676 krb5_free_unparsed_name(context,cname);
1677 krb5_free_unparsed_name(context,sname);
1680 my_creds.client = me;
1681 my_creds.server = server;
1683 code = krb5_get_renewed_creds(context, &my_creds, me, cc, NULL);
1685 DebugPrintf("krb5_get_renewed_creds() failed: %d\n", code);
1689 code = krb5_cc_initialize(context, cc, me);
1691 DebugPrintf("krb5_cc_initialize() failed: %d\n", code);
1695 code = krb5_cc_store_cred(context, cc, &my_creds);
1697 DebugPrintf("krb5_cc_store_cred() failed: %d\n", code);
1702 if (my_creds.client == me)
1703 my_creds.client = 0;
1704 if (my_creds.server == server)
1705 my_creds.server = 0;
1706 krb5_free_cred_contents(context, &my_creds);
1708 krb5_free_principal(context, me);
1710 krb5_free_principal(context, server);
1711 if (cc && (cc != alt_cc))
1712 krb5_cc_close(context, cc);
1713 if (context && (context != alt_context))
1714 krb5_free_context(context);
1719 KFW_kinit( krb5_context alt_context,
1722 char *principal_name,
1724 krb5_deltat lifetime,
1727 krb5_deltat renew_life,
1731 krb5_error_code code = 0;
1732 krb5_context context = NULL;
1733 krb5_ccache cc = NULL;
1734 krb5_principal me = NULL;
1736 krb5_creds my_creds;
1737 krb5_get_init_creds_opt *options = NULL;
1738 krb5_addresses addrs = {0, NULL};
1739 int i = 0, addr_count = 0;
1741 memset(&my_creds, 0, sizeof(my_creds));
1744 context = alt_context;
1746 code = krb5_init_context(&context);
1747 if (code) goto cleanup;
1753 code = krb5_cc_default(context, &cc);
1754 if (code) goto cleanup;
1757 code = krb5_get_init_creds_opt_alloc(context, &options);
1758 if (code) goto cleanup;
1760 code = krb5_parse_name(context, principal_name, &me);
1761 if (code) goto cleanup;
1763 code = krb5_unparse_name(context, me, &name);
1764 if (code) goto cleanup;
1767 lifetime = KFW_get_default_lifetime(context,
1768 krb5_principal_get_realm(context, me));
1776 krb5_get_init_creds_opt_set_tkt_life(options, lifetime);
1777 krb5_get_init_creds_opt_set_forwardable(options, forwardable ? 1 : 0);
1778 krb5_get_init_creds_opt_set_proxiable(options, proxiable ? 1 : 0);
1779 krb5_get_init_creds_opt_set_renew_life(options, renew_life);
1781 krb5_get_init_creds_opt_set_addressless(context, options, TRUE);
1784 // we are going to add the public IP address specified by the user
1785 // to the list provided by the operating system
1786 struct sockaddr_in in_addr;
1788 krb5_addresses addr_l;
1790 krb5_get_all_client_addrs(context, &addrs);
1792 in_addr.sin_family = AF_INET;
1793 in_addr.sin_port = 0;
1794 in_addr.sin_addr.S_un.S_addr = htonl(publicIP);
1796 code = krb5_sockaddr2address(context, (struct sockaddr *)&in_addr,
1803 code = krb5_append_addresses(context, &addrs, &addr_l);
1805 krb5_free_address(context, &addr);
1808 krb5_get_init_creds_opt_set_address_list(options, &addrs);
1812 code = krb5_get_init_creds_password(context,
1815 password, // password
1816 KRB5_prompter, // prompter
1817 hParent, // prompter data
1824 code = krb5_cc_initialize(context, cc, me);
1828 code = krb5_cc_store_cred(context, cc, &my_creds);
1833 if ( addrs.len > 0 )
1834 krb5_free_addresses(context, &addrs);
1836 if (my_creds.client == me)
1837 my_creds.client = 0;
1839 krb5_free_cred_contents(context, &my_creds);
1841 krb5_free_unparsed_name(context, name);
1843 krb5_free_principal(context, me);
1845 krb5_get_init_creds_opt_free(context, options);
1846 if (cc && (cc != alt_cc))
1847 krb5_cc_close(context, cc);
1848 if (context && (context != alt_context))
1849 krb5_free_context(context);
1855 KFW_kdestroy(krb5_context alt_context, krb5_ccache alt_cc)
1857 krb5_context context = NULL;
1858 krb5_ccache cc = NULL;
1859 krb5_error_code code;
1862 context = alt_context;
1864 code = krb5_init_context(&context);
1865 if (code) goto cleanup;
1871 code = krb5_cc_default(context, &cc);
1872 if (code) goto cleanup;
1875 code = krb5_cc_destroy(context, cc);
1876 if ( !code ) cc = 0;
1879 if (cc && (cc != alt_cc))
1880 krb5_cc_close(context, cc);
1881 if (context && (context != alt_context))
1882 krb5_free_context(context);
1890 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1892 NTSTATUS Status = 0;
1894 TOKEN_STATISTICS Stats;
1900 *ppSessionData = NULL;
1902 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1906 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1907 CloseHandle( TokenHandle );
1911 Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1912 if ( FAILED(Status) || !ppSessionData )
1919 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
1920 // cache. It validates whether or not it is reasonable to assume that if we
1921 // attempted to retrieve valid tickets we could do so. Microsoft does not
1922 // automatically renew expired tickets. Therefore, the cache could contain
1923 // expired or invalid tickets. Microsoft also caches the user's password
1924 // and will use it to retrieve new TGTs if the cache is empty and tickets
1928 MSLSA_IsKerberosLogon(VOID)
1930 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
1931 BOOL Success = FALSE;
1933 if ( GetSecurityLogonSessionData(&pSessionData) ) {
1934 if ( pSessionData->AuthenticationPackage.Buffer ) {
1940 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
1941 usLength = (pSessionData->AuthenticationPackage).Length;
1944 StringCbCopyNW( buffer, sizeof(buffer)/sizeof(WCHAR),
1945 usBuffer, usLength);
1946 if ( !lstrcmpW(L"Kerberos",buffer) )
1950 LsaFreeReturnBuffer(pSessionData);
1954 #endif /* USE_MS2MIT */
1956 static BOOL CALLBACK
1957 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
1961 switch ( message ) {
1963 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
1965 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
1968 for ( i=0; i < mid_cnt ; i++ ) {
1969 if (mid_tb[i].echo == 0)
1970 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
1971 else if (mid_tb[i].echo == 2)
1972 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
1977 switch ( LOWORD(wParam) ) {
1979 for ( i=0; i < mid_cnt ; i++ ) {
1980 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
1981 *mid_tb[i].buf = '\0';
1985 EndDialog(hDialog, LOWORD(wParam));
1993 lpwAlign( LPWORD lpIn )
1997 ul = (ULONG_PTR) lpIn;
2001 return (LPWORD) ul;;
2005 * dialog widths are measured in 1/4 character widths
2006 * dialog height are measured in 1/8 character heights
2010 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2011 char * ptext[], int numlines, int width,
2012 int tb_cnt, struct textField * tb)
2016 LPDLGITEMTEMPLATE lpdit;
2022 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2029 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2031 // Define a dialog box.
2033 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2034 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2035 | DS_SETFOREGROUND | DS_3DLOOK
2036 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2037 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2040 lpdt->cx = 20 + width * 4;
2041 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2043 lpw = (LPWORD) (lpdt + 1);
2044 *lpw++ = 0; // no menu
2045 *lpw++ = 0; // predefined dialog box class (by default)
2047 lpwsz = (LPWSTR) lpw;
2048 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2050 *lpw++ = 8; // font size (points)
2051 lpwsz = (LPWSTR) lpw;
2052 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2056 //-----------------------
2057 // Define an OK button.
2058 //-----------------------
2059 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2060 lpdit = (LPDLGITEMTEMPLATE) lpw;
2061 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2062 lpdit->dwExtendedStyle = 0;
2063 lpdit->x = (lpdt->cx - 14)/4 - 20;
2064 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2067 lpdit->id = IDOK; // OK button identifier
2069 lpw = (LPWORD) (lpdit + 1);
2071 *lpw++ = 0x0080; // button class
2073 lpwsz = (LPWSTR) lpw;
2074 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2076 *lpw++ = 0; // no creation data
2078 //-----------------------
2079 // Define an Cancel button.
2080 //-----------------------
2081 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2082 lpdit = (LPDLGITEMTEMPLATE) lpw;
2083 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2084 lpdit->dwExtendedStyle = 0;
2085 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2086 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2089 lpdit->id = IDCANCEL; // CANCEL button identifier
2091 lpw = (LPWORD) (lpdit + 1);
2093 *lpw++ = 0x0080; // button class
2095 lpwsz = (LPWSTR) lpw;
2096 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2098 *lpw++ = 0; // no creation data
2100 /* Add controls for preface data */
2101 for ( i=0; i<numlines; i++) {
2102 /*-----------------------
2103 * Define a static text control.
2104 *-----------------------*/
2105 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2106 lpdit = (LPDLGITEMTEMPLATE) lpw;
2107 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2108 lpdit->dwExtendedStyle = 0;
2110 lpdit->y = 10 + i * 14;
2111 lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2113 lpdit->id = ID_TEXT + i; // text identifier
2115 lpw = (LPWORD) (lpdit + 1);
2117 *lpw++ = 0x0082; // static class
2119 lpwsz = (LPWSTR) lpw;
2120 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2121 -1, lpwsz, 2*width);
2123 *lpw++ = 0; // no creation data
2126 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2127 int len = (int)strlen(tb[i].label);
2132 for ( i=0; i<tb_cnt; i++) {
2134 /*-----------------------
2135 * Define a static text control.
2136 *-----------------------*/
2137 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2138 lpdit = (LPDLGITEMTEMPLATE) lpw;
2139 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2140 lpdit->dwExtendedStyle = 0;
2142 lpdit->y = 10 + (numlines + i + 1) * 14;
2143 lpdit->cx = pwid * 4;
2145 lpdit->id = ID_TEXT + numlines + i; // text identifier
2147 lpw = (LPWORD) (lpdit + 1);
2149 *lpw++ = 0x0082; // static class
2151 lpwsz = (LPWSTR) lpw;
2152 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2155 *lpw++ = 0; // no creation data
2157 /*-----------------------
2158 * Define an edit control.
2159 *-----------------------*/
2160 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2161 lpdit = (LPDLGITEMTEMPLATE) lpw;
2162 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2163 lpdit->dwExtendedStyle = 0;
2164 lpdit->x = 10 + (pwid + 1) * 4;
2165 lpdit->y = 10 + (numlines + i + 1) * 14;
2166 lpdit->cx = (width - (pwid + 1)) * 4;
2168 lpdit->id = ID_MID_TEXT + i; // identifier
2170 lpw = (LPWORD) (lpdit + 1);
2172 *lpw++ = 0x0081; // edit class
2174 lpwsz = (LPWSTR) lpw;
2175 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2178 *lpw++ = 0; // no creation data
2182 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2183 hwndOwner, (DLGPROC) MultiInputDialogProc);
2187 case 0: /* Timeout */
2195 StringCbPrintf(buf, sizeof(buf), "DialogBoxIndirect() failed: %d", GetLastError());
2196 MessageBox(hwndOwner,
2199 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2206 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2208 HINSTANCE hInst = 0;
2209 size_t maxwidth = 0;
2212 char * plines[16], *p = preface ? preface : "";
2215 for ( i=0; i<16; i++ )
2218 while (*p && numlines < 16) {
2219 plines[numlines++] = p;
2220 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2221 if ( *p == '\r' && *(p+1) == '\n' ) {
2224 } else if ( *p == '\n' ) {
2227 if ( strlen(plines[numlines-1]) > maxwidth )
2228 maxwidth = strlen(plines[numlines-1]);
2231 for ( i=0;i<n;i++ ) {
2232 len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2233 if ( maxwidth < len )
2237 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2240 static krb5_error_code KRB5_CALLCONV
2241 KRB5_prompter( krb5_context context,
2246 krb5_prompt prompts[])
2248 krb5_error_code errcode = 0;
2250 struct textField * tb = NULL;
2251 int len = 0, blen=0, nlen=0;
2252 HWND hParent = (HWND)data;
2255 nlen = (int)strlen(name)+2;
2258 blen = (int)strlen(banner)+2;
2260 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2263 memset(tb,0,sizeof(struct textField) * num_prompts);
2264 for ( i=0; i < num_prompts; i++ ) {
2265 tb[i].buf = prompts[i].reply->data;
2266 tb[i].len = prompts[i].reply->length;
2267 tb[i].label = prompts[i].prompt;
2269 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2272 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2274 for ( i=0; i < num_prompts; i++ )
2275 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2283 for (i = 0; i < num_prompts; i++) {
2284 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2291 KFW_AFS_wait_for_service_start(void)
2296 CurrentState = SERVICE_START_PENDING;
2297 memset(HostName, '\0', sizeof(HostName));
2298 gethostname(HostName, sizeof(HostName));
2300 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2302 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2304 if ( IsDebuggerPresent() ) {
2305 switch ( CurrentState ) {
2306 case SERVICE_STOPPED:
2307 OutputDebugString("SERVICE_STOPPED\n");
2309 case SERVICE_START_PENDING:
2310 OutputDebugString("SERVICE_START_PENDING\n");
2312 case SERVICE_STOP_PENDING:
2313 OutputDebugString("SERVICE_STOP_PENDING\n");
2315 case SERVICE_RUNNING:
2316 OutputDebugString("SERVICE_RUNNING\n");
2318 case SERVICE_CONTINUE_PENDING:
2319 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2321 case SERVICE_PAUSE_PENDING:
2322 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2324 case SERVICE_PAUSED:
2325 OutputDebugString("SERVICE_PAUSED\n");
2328 OutputDebugString("UNKNOWN Service State\n");
2331 if (CurrentState == SERVICE_STOPPED)
2333 if (CurrentState == SERVICE_RUNNING)
2349 memset(HostName, '\0', sizeof(HostName));
2350 gethostname(HostName, sizeof(HostName));
2351 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2353 if (CurrentState != SERVICE_RUNNING)
2356 rc = ktc_ForgetAllTokens();
2362 #define ALLOW_REGISTER 1
2364 ViceIDToUsername(char *username,
2365 char *realm_of_user,
2366 char *realm_of_cell,
2368 struct ktc_principal *aclient,
2369 struct ktc_principal *aserver,
2370 struct ktc_token *atoken)
2372 static char lastcell[CELL_MAXNAMELEN+1] = { 0 };
2373 static char confdir[512] = { 0 };
2374 #ifdef AFS_ID_TO_NAME
2375 char username_copy[BUFSIZ];
2376 #endif /* AFS_ID_TO_NAME */
2377 long viceId = ANONYMOUSID; /* AFS uid of user */
2379 #ifdef ALLOW_REGISTER
2381 #endif /* ALLOW_REGISTER */
2383 if (confdir[0] == '\0')
2384 cm_GetConfigDir(confdir, sizeof(confdir));
2386 StringCbCopyN( lastcell, sizeof(lastcell),
2387 aserver->cell, sizeof(lastcell) - 1);
2389 if (!pr_Initialize (0, confdir, aserver->cell)) {
2390 char sname[PR_MAXNAMELEN];
2391 StringCbCopyN( sname, sizeof(sname),
2392 username, sizeof(sname) - 1);
2393 status = pr_SNameToId (sname, &viceId);
2398 * This is a crock, but it is Transarc's crock, so
2399 * we have to play along in order to get the
2400 * functionality. The way the afs id is stored is
2401 * as a string in the username field of the token.
2402 * Contrary to what you may think by looking at
2403 * the code for tokens, this hack (AFS ID %d) will
2404 * not work if you change %d to something else.
2408 * This code is taken from cklog -- it lets people
2409 * automatically register with the ptserver in foreign cells
2412 #ifdef ALLOW_REGISTER
2414 if (viceId != ANONYMOUSID) {
2415 #else /* ALLOW_REGISTER */
2416 if ((status == 0) && (viceId != ANONYMOUSID))
2417 #endif /* ALLOW_REGISTER */
2419 #ifdef AFS_ID_TO_NAME
2420 StringCbCopyN( username_copy, sizeof(username_copy),
2421 username, sizeof(username_copy) - 1);
2422 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2423 #endif /* AFS_ID_TO_NAME */
2425 #ifdef ALLOW_REGISTER
2426 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2428 StringCbCopyN( aclient->name, sizeof(aclient->name),
2429 username, sizeof(aclient->name) - 1);
2430 aclient->instance[0] = '\0';
2431 StringCbCopyN( aclient->cell, sizeof(aclient->cell),
2432 realm_of_user, sizeof(aclient->cell) - 1);
2433 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2435 if (status = pr_Initialize(1L, confdir, aserver->cell))
2437 status = pr_CreateUser(username, &id);
2441 #ifdef AFS_ID_TO_NAME
2442 StringCbCopyN( username_copy, sizeof(username_copy),
2443 username, sizeof(username_copy) - 1);
2444 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2445 #endif /* AFS_ID_TO_NAME */
2448 #endif /* ALLOW_REGISTER */
2454 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
2459 ret = decode_Ticket(v5cred->ticket.data, v5cred->ticket.length,
2462 StringCbCopy(dest, destlen, ticket.realm);
2464 free_Ticket(&ticket);
2470 krb5_context alt_context,
2475 int lifetime, /* unused parameter */
2480 struct ktc_principal aserver;
2481 struct ktc_principal aclient;
2482 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2483 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2484 char local_cell[CELL_MAXNAMELEN+1];
2485 char Dmycell[CELL_MAXNAMELEN+1];
2486 struct ktc_token atoken;
2487 struct ktc_token btoken;
2488 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2489 char RealmName[128];
2491 char ServiceName[128];
2494 krb5_context context = NULL;
2495 krb5_ccache cc = NULL;
2497 krb5_creds * k5creds = NULL;
2498 krb5_error_code code;
2499 krb5_principal client_principal = NULL;
2500 krb5_data * k5data = NULL;
2501 unsigned int retry = 0;
2504 memset(HostName, '\0', sizeof(HostName));
2505 gethostname(HostName, sizeof(HostName));
2506 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2507 if ( IsDebuggerPresent() )
2508 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2511 if (CurrentState != SERVICE_RUNNING) {
2512 if ( IsDebuggerPresent() )
2513 OutputDebugString("AFSD Service NOT RUNNING\n");
2517 memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
2518 memset(RealmName, '\0', sizeof(RealmName));
2519 memset(CellName, '\0', sizeof(CellName));
2520 memset(ServiceName, '\0', sizeof(ServiceName));
2521 memset(realm_of_user, '\0', sizeof(realm_of_user));
2522 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2523 if (cell && cell[0])
2524 StringCbCopyN( Dmycell, sizeof(Dmycell),
2525 cell, sizeof(Dmycell) - 1);
2527 memset(Dmycell, '\0', sizeof(Dmycell));
2529 // NULL or empty cell returns information on local cell
2530 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2532 // KFW_AFS_error(rc, "get_cellconfig()");
2536 if ( alt_context ) {
2537 context = alt_context;
2539 code = krb5_init_context(&context);
2540 if (code) goto cleanup;
2546 code = krb5_cc_default(context, &cc);
2551 memset(&increds, 0, sizeof(increds));
2553 code = krb5_cc_get_principal(context, cc, &client_principal);
2555 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2557 OutputDebugString("Principal Not Found for ccache\n");
2562 if (!KFW_accept_dotted_usernames()) {
2564 /* look for client principals which cannot be distinguished
2565 * from Kerberos 4 multi-component principal names
2567 comp = krb5_principal_get_comp_string(context,client_principal,0);
2568 if (strchr(comp, '.') != NULL) {
2569 OutputDebugString("Illegal Principal name contains dot in first component\n");
2570 rc = KRB5KRB_ERR_GENERIC;
2575 StringCbCopy(realm_of_user, sizeof(realm_of_user),
2576 krb5_principal_get_realm(context, client_principal));
2578 StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
2579 afs_realm_of_cell(context, &ak_cellconfig),
2580 sizeof(realm_of_cell) - 1);
2582 if (strlen(service) == 0)
2583 StringCbCopy( ServiceName, sizeof(ServiceName), "afs");
2585 StringCbCopyN( ServiceName, sizeof(ServiceName),
2586 service, sizeof(ServiceName) - 1);
2588 if (strlen(cell) == 0)
2589 StringCbCopyN( CellName, sizeof(CellName),
2590 local_cell, sizeof(CellName) - 1);
2592 StringCbCopyN( CellName, sizeof(CellName),
2593 cell, sizeof(CellName) - 1);
2595 /* This is for Kerberos v4 only */
2596 if (strlen(realm) == 0)
2597 StringCbCopyN( RealmName, sizeof(RealmName),
2598 realm_of_cell, sizeof(RealmName) - 1);
2600 StringCbCopyN( RealmName, sizeof(RealmName),
2601 realm, sizeof(RealmName) - 1);
2603 code = KRB5KRB_ERR_GENERIC;
2605 increds.client = client_principal;
2606 increds.times.endtime = 0;
2607 /* Ask for DES since that is what V4 understands */
2608 increds.session.keytype = ENCTYPE_DES_CBC_CRC;
2610 /* ALWAYS first try service/cell@CLIENT_REALM */
2611 if (code = krb5_build_principal(context, &increds.server,
2612 (int)strlen(realm_of_user),
2621 if ( IsDebuggerPresent() ) {
2622 char * cname, *sname;
2623 krb5_unparse_name(context, increds.client, &cname);
2624 krb5_unparse_name(context, increds.server, &sname);
2625 OutputDebugString("Getting tickets for \"");
2626 OutputDebugString(cname);
2627 OutputDebugString("\" and service \"");
2628 OutputDebugString(sname);
2629 OutputDebugString("\"\n");
2630 krb5_free_unparsed_name(context,cname);
2631 krb5_free_unparsed_name(context,sname);
2634 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2637 * The client's realm is a local realm for the cell.
2638 * Save it so that later the pts registration will not
2641 StringCbCopyN(realm_of_cell, sizeof(realm_of_cell),
2642 realm_of_user, sizeof(realm_of_cell) - 1);
2645 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2646 code == KRB5_ERR_HOST_REALM_UNKNOWN ||
2647 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2648 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2650 * If there was a specific realm we are supposed to try
2653 if (strlen(realm) != 0) {
2654 /* service/cell@REALM */
2656 code = krb5_build_principal(context, &increds.server,
2662 if ( IsDebuggerPresent() ) {
2663 char * cname, *sname;
2664 krb5_unparse_name(context, increds.client, &cname);
2665 krb5_unparse_name(context, increds.server, &sname);
2666 OutputDebugString("Getting tickets for \"");
2667 OutputDebugString(cname);
2668 OutputDebugString("\" and service \"");
2669 OutputDebugString(sname);
2670 OutputDebugString("\"\n");
2671 krb5_free_unparsed_name(context,cname);
2672 krb5_free_unparsed_name(context,sname);
2676 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2678 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2679 code == KRB5_ERR_HOST_REALM_UNKNOWN ||
2680 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2681 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2682 /* Or service@REALM */
2683 krb5_free_principal(context,increds.server);
2685 code = krb5_build_principal(context, &increds.server,
2691 if ( IsDebuggerPresent() ) {
2692 char * cname, *sname;
2693 krb5_unparse_name(context, increds.client, &cname);
2694 krb5_unparse_name(context, increds.server, &sname);
2695 DebugPrintf("Getting tickets for \"%s\" and service \"%s\"\n", cname, sname);
2696 krb5_free_unparsed_name(context,cname);
2697 krb5_free_unparsed_name(context,sname);
2701 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2705 /* we have a local realm for the cell */
2706 StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
2707 realm, sizeof(realm_of_cell) - 1);
2710 if (strcmp(realm_of_user, realm_of_cell)) {
2711 /* Then service/cell@CELL_REALM */
2712 krb5_free_principal(context,increds.server);
2714 code = krb5_build_principal(context, &increds.server,
2715 (int)strlen(realm_of_cell),
2720 if ( IsDebuggerPresent()) {
2721 char * cname, *sname;
2722 krb5_unparse_name(context, increds.client, &cname);
2723 krb5_unparse_name(context, increds.server, &sname);
2724 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2725 OutputDebugString("Trying again: getting tickets for \"");
2726 OutputDebugString(cname);
2727 OutputDebugString("\" and service \"");
2728 OutputDebugString(sname);
2729 OutputDebugString("\"\n");
2730 krb5_free_unparsed_name(context,cname);
2731 krb5_free_unparsed_name(context,sname);
2735 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2737 if (!code && !strlen(realm_of_cell))
2738 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
2742 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2743 code == KRB5_ERR_HOST_REALM_UNKNOWN ||
2744 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2745 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2746 /* Finally service@CELL_REALM */
2747 krb5_free_principal(context,increds.server);
2749 code = krb5_build_principal(context, &increds.server,
2750 (int)strlen(realm_of_cell),
2755 if ( IsDebuggerPresent() ) {
2756 char * cname, *sname;
2757 krb5_unparse_name(context, increds.client, &cname);
2758 krb5_unparse_name(context, increds.server, &sname);
2759 DebugPrintf("krb5_get_credentials() returned Service Principal Unknown\n"
2760 "Trying again: getting tickets for \"%s\" and service \"%s\"\n", cname, sname);
2761 krb5_free_unparsed_name(context,cname);
2762 krb5_free_unparsed_name(context,sname);
2766 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2767 if (!code && !strlen(realm_of_cell))
2768 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
2773 DebugPrintf("krb5_get_credentials returns: %d\n", code);
2777 /* This code inserts the entire K5 ticket into the token */
2778 memset(&aserver, '\0', sizeof(aserver));
2779 StringCbCopyN(aserver.name, sizeof(aserver.name),
2780 ServiceName, sizeof(aserver.name) - 1);
2781 StringCbCopyN(aserver.cell, sizeof(aserver.cell),
2782 CellName, sizeof(aserver.cell) - 1);
2784 memset(&atoken, '\0', sizeof(atoken));
2785 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2786 atoken.startTime = k5creds->times.starttime;
2787 atoken.endTime = k5creds->times.endtime;
2788 memcpy(&atoken.sessionKey,
2789 k5creds->session.keyvalue.data,
2790 k5creds->session.keyvalue.length);
2791 atoken.ticketLen = k5creds->ticket.length;
2792 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2795 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2796 if ( IsDebuggerPresent() ) {
2798 StringCbPrintf(message, sizeof(message), "ktc_GetToken returns: %d\n", rc);
2799 OutputDebugString(message);
2801 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2802 if ( rc == KTC_NOCM && retry < 20 ) {
2805 goto retry_gettoken5;
2810 if (atoken.kvno == btoken.kvno &&
2811 atoken.ticketLen == btoken.ticketLen &&
2812 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2813 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2815 /* Success - Nothing to do */
2819 // * Reset the "aclient" structure before we call ktc_SetToken.
2820 // * This structure was first set by the ktc_GetToken call when
2821 // * we were comparing whether identical tokens already existed.
2823 StringCbCopy(aclient.name, sizeof(aclient.name),
2824 krb5_principal_get_comp_string(context, k5creds->client, 0));
2826 if ( krb5_principal_get_num_comp(context, k5creds->client) > 1 ) {
2827 StringCbCat(aclient.name, sizeof(aclient.name), ".");
2828 StringCbCat(aclient.name, sizeof(aclient.name),
2829 krb5_principal_get_comp_string(context, k5creds->client, 1));
2831 aclient.instance[0] = '\0';
2833 StringCbCopyN(aclient.cell, sizeof(aclient.cell),
2834 realm_of_cell, sizeof(aclient.cell) - 1);
2836 /* For Khimaira, always append the realm name */
2837 StringCbCat(aclient.name, sizeof(aclient.name), "@");
2838 StringCbCat(aclient.name, sizeof(aclient.name),
2839 krb5_principal_get_realm(context, k5creds->client));
2841 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
2842 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
2843 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
2844 &aclient, &aserver, &atoken);
2847 StringCbCopyN(aclient.smbname, sizeof(aclient.smbname),
2848 smbname, sizeof(aclient.smbname) - 1);
2850 aclient.smbname[0] = '\0';
2852 if ( IsDebuggerPresent() ) {
2854 StringCbPrintf(message, sizeof(message), "aclient.name: %s\n", aclient.name);
2855 OutputDebugString(message);
2856 StringCbPrintf(message, sizeof(message), "aclient.smbname: %s\n", aclient.smbname);
2857 OutputDebugString(message);
2860 rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
2863 if (client_principal)
2864 krb5_free_principal(context,client_principal);
2865 /* increds.client == client_principal */
2867 krb5_free_principal(context,increds.server);
2868 if (cc && (cc != alt_cc))
2869 krb5_cc_close(context, cc);
2870 if (context && (context != alt_context))
2871 krb5_free_context(context);
2872 if (ak_cellconfig.linkedCell)
2873 free(ak_cellconfig.linkedCell);
2875 return(rc? rc : code);
2878 /**************************************/
2879 /* afs_realm_of_cell(): */
2880 /**************************************/
2882 afs_realm_of_cell(krb5_context context, struct afsconf_cell *cellconfig)
2884 static char krbrlm[REALM_SZ+1]="";
2885 char ** realmlist=NULL;
2891 r = krb5_get_host_realm(context, cellconfig->hostName[0], &realmlist);
2892 if ( !r && realmlist && realmlist[0] ) {
2893 StringCbCopyN( krbrlm, sizeof(krbrlm),
2894 realmlist[0], sizeof(krbrlm) - 1);
2895 krb5_free_host_realm(context, realmlist);
2901 char *t = cellconfig->name;
2906 if (islower(c)) c=toupper(c);
2914 /**************************************/
2915 /* KFW_AFS_get_cellconfig(): */
2916 /**************************************/
2918 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
2921 char newcell[CELL_MAXNAMELEN+1];
2922 char linkedcell[CELL_MAXNAMELEN+1]="";
2924 local_cell[0] = (char)0;
2925 memset(cellconfig, 0, sizeof(*cellconfig));
2927 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
2928 if (rc = cm_GetRootCellName(local_cell))
2933 if (strlen(cell) == 0)
2934 StringCbCopy(cell, CELL_MAXNAMELEN, local_cell);
2936 rc = cm_SearchCellRegistry(1, cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
2937 if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
2938 rc = cm_SearchCellFileEx(cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
2941 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
2945 StringCbCopyN( cellconfig->name, sizeof(cellconfig->name),
2946 newcell, sizeof(cellconfig->name) - 1);
2948 cellconfig->linkedCell = strdup(linkedcell);
2953 /**************************************/
2954 /* get_cellconfig_callback(): */
2955 /**************************************/
2957 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep, unsigned short ipRank)
2959 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
2961 cc->hostAddr[cc->numServers] = *addrp;
2962 StringCbCopyN( cc->hostName[cc->numServers], sizeof(cc->hostName[cc->numServers]),
2963 namep, sizeof(cc->hostName[cc->numServers]) - 1);
2969 /**************************************/
2970 /* KFW_AFS_error(): */
2971 /**************************************/
2973 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
2976 const char *errText;
2978 // Using AFS defines as error messages for now, until Transarc
2979 // gets back to me with "string" translations of each of these
2981 if (rc == KTC_ERROR)
2982 errText = "KTC_ERROR";
2983 else if (rc == KTC_TOOBIG)
2984 errText = "KTC_TOOBIG";
2985 else if (rc == KTC_INVAL)
2986 errText = "KTC_INVAL";
2987 else if (rc == KTC_NOENT)
2988 errText = "KTC_NOENT";
2989 else if (rc == KTC_PIOCTLFAIL)
2990 errText = "KTC_PIOCTLFAIL";
2991 else if (rc == KTC_NOPIOCTL)
2992 errText = "KTC_NOPIOCTL";
2993 else if (rc == KTC_NOCELL)
2994 errText = "KTC_NOCELL";
2995 else if (rc == KTC_NOCM)
2996 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
2998 errText = "Unknown error!";
3000 StringCbPrintf(message, sizeof(message), "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3002 if ( IsDebuggerPresent() ) {
3003 OutputDebugString(message);
3004 OutputDebugString("\n");
3006 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3012 LPSTR lpszMachineName,
3013 LPSTR lpszServiceName,
3014 DWORD *lpdwCurrentState)
3017 SC_HANDLE schSCManager = NULL;
3018 SC_HANDLE schService = NULL;
3019 DWORD fdwDesiredAccess = 0;
3020 SERVICE_STATUS ssServiceStatus = {0};
3023 *lpdwCurrentState = 0;
3025 fdwDesiredAccess = GENERIC_READ;
3027 schSCManager = OpenSCManager(lpszMachineName,
3031 if(schSCManager == NULL)
3033 hr = GetLastError();
3037 schService = OpenService(schSCManager,
3041 if(schService == NULL)
3043 hr = GetLastError();
3047 fRet = QueryServiceStatus(schService,
3052 hr = GetLastError();
3056 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3060 CloseServiceHandle(schService);
3061 CloseServiceHandle(schSCManager);
3066 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3068 krb5_context context = NULL;
3069 krb5_ccache cc = NULL;
3070 krb5_error_code code;
3072 const char * realm = NULL;
3073 krb5_principal principal = NULL;
3074 char * pname = NULL;
3075 char password[PROBE_PASSWORD_LEN+1];
3076 BOOL serverReachable = 0;
3078 code = krb5_init_context(&context);
3079 if (code) goto cleanup;
3082 realm = afs_realm_of_cell(context, cellconfig); // do not free
3084 code = krb5_build_principal(context, &principal, (int)strlen(realm),
3085 realm, PROBE_USERNAME, NULL, NULL);
3086 if ( code ) goto cleanup;
3088 code = KFW_get_ccache(context, principal, &cc);
3089 if ( code ) goto cleanup;
3091 code = krb5_unparse_name(context, principal, &pname);
3092 if ( code ) goto cleanup;
3094 pwdata.data = password;
3095 pwdata.length = PROBE_PASSWORD_LEN;
3096 krb5_c_random_make_octets(context, &pwdata);
3099 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3100 if (password[i] == '\0')
3103 password[PROBE_PASSWORD_LEN] = '\0';
3105 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3115 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3116 case KRB5KDC_ERR_CLIENT_REVOKED:
3117 case KRB5KDC_ERR_CLIENT_NOTYET:
3118 case KRB5KDC_ERR_PREAUTH_FAILED:
3119 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3120 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3121 serverReachable = TRUE;
3124 serverReachable = FALSE;
3129 krb5_free_unparsed_name(context,pname);
3131 krb5_free_principal(context,principal);
3133 krb5_cc_close(context,cc);
3135 krb5_free_context(context);
3137 return serverReachable;
3141 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3143 krb5_context context = NULL;
3144 krb5_error_code code;
3145 krb5_ccache mslsa_ccache=NULL;
3146 krb5_principal princ = NULL;
3147 char * pname = NULL;
3150 if (!KFW_is_available())
3153 if (code = krb5_init_context(&context))
3156 if (code = krb5_cc_resolve(context, "MSLSA:", &mslsa_ccache))
3159 if (code = krb5_cc_get_principal(context, mslsa_ccache, &princ))
3162 if (code = krb5_unparse_name(context, princ, &pname))
3165 if ( strlen(pname) < *dwSize ) {
3166 StringCbCopyN(szUser, *dwSize, pname, (*dwSize) - 1);
3169 *dwSize = (DWORD)strlen(pname);
3173 krb5_free_unparsed_name(context, pname);
3176 krb5_free_principal(context, princ);
3179 krb5_cc_close(context, mslsa_ccache);
3182 krb5_free_context(context);
3187 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3189 // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3190 PSID pSystemSID = NULL;
3191 DWORD SystemSIDlength = 0, UserSIDlength = 0;
3192 PACL ccacheACL = NULL;
3193 DWORD ccacheACLlength = 0;
3194 PTOKEN_USER pTokenUser = NULL;
3203 /* Get System SID */
3204 if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3210 SystemSIDlength = GetLengthSid(pSystemSID);
3211 ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3212 + SystemSIDlength - sizeof(DWORD);
3215 if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3217 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3218 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3220 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3225 UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3227 ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
3232 ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3237 InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3238 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3239 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3242 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3243 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3244 pTokenUser->User.Sid);
3245 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3246 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3251 gle = GetLastError();
3252 if (gle != ERROR_NO_TOKEN)
3255 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3256 OWNER_SECURITY_INFORMATION,
3257 pTokenUser->User.Sid,
3261 gle = GetLastError();
3262 if (gle != ERROR_NO_TOKEN)
3266 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3267 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3272 gle = GetLastError();
3273 if (gle != ERROR_NO_TOKEN)
3280 LocalFree(pSystemSID);
3282 LocalFree(pTokenUser);
3284 LocalFree(ccacheACL);
3289 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3292 DWORD dwSize = size-1; /* leave room for nul */
3295 if (!hUserToken || !newfilename || size <= 0)
3298 *newfilename = '\0';
3300 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3301 if ( !dwLen || dwLen > dwSize )
3302 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3303 if ( !dwLen || dwLen > dwSize )
3306 newfilename[dwSize] = '\0';
3311 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3313 char filename[MAX_PATH] = "";
3315 char cachename[MAX_PATH + 8] = "FILE:";
3316 krb5_context context = NULL;
3317 krb5_error_code code;
3318 krb5_principal princ = NULL;
3319 krb5_ccache cc = NULL;
3320 krb5_ccache ncc = NULL;
3322 if (!user || !szLogonId)
3325 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3326 if ( count > sizeof(filename) || count == 0 ) {
3327 GetWindowsDirectory(filename, sizeof(filename));
3330 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3333 StringCbCat( filename, sizeof(filename), "\\");
3334 StringCbCat( filename, sizeof(filename), szLogonId);
3336 StringCbCat( cachename, sizeof(cachename), filename);
3338 DeleteFile(filename);
3340 code = krb5_init_context(&context);
3341 if (code) goto cleanup;
3343 code = krb5_parse_name(context, user, &princ);
3344 if (code) goto cleanup;
3346 code = KFW_get_ccache(context, princ, &cc);
3347 if (code) goto cleanup;
3349 code = krb5_cc_resolve(context, cachename, &ncc);
3350 if (code) goto cleanup;
3352 code = krb5_cc_initialize(context, ncc, princ);
3353 if (code) goto cleanup;
3355 code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3356 if (code) goto cleanup;
3358 code = krb5_cc_copy_creds(context,cc,ncc);
3362 krb5_cc_close(context, cc);
3366 krb5_cc_close(context, ncc);
3370 krb5_free_principal(context, princ);
3375 krb5_free_context(context);
3379 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3381 char cachename[MAX_PATH + 8] = "FILE:";
3382 krb5_context context = NULL;
3383 krb5_error_code code;
3384 krb5_principal princ = NULL;
3385 krb5_ccache cc = NULL;
3386 krb5_ccache ncc = NULL;
3392 if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3395 code = krb5_init_context(&context);
3398 StringCbCat( cachename, sizeof(cachename), filename);
3400 code = krb5_cc_resolve(context, cachename, &cc);
3401 if (code) goto cleanup;
3403 code = krb5_cc_get_principal(context, cc, &princ);
3405 code = krb5_cc_default(context, &ncc);
3407 code = krb5_cc_initialize(context, ncc, princ);
3410 code = krb5_cc_copy_creds(context,cc,ncc);
3413 krb5_cc_close(context, ncc);
3417 retval=0; /* success */
3421 krb5_cc_close(context, cc);
3425 DeleteFile(filename);
3428 krb5_free_principal(context, princ);
3433 krb5_free_context(context);
3438 /* We are including this
3440 /* Ticket lifetime. This defines the table used to lookup lifetime for the
3441 fixed part of rande of the one byte lifetime field. Values less than 0x80
3442 are intrpreted as the number of 5 minute intervals. Values from 0x80 to
3443 0xBF should be looked up in this table. The value of 0x80 is the same using
3444 both methods: 10 and two-thirds hours . The lifetime of 0xBF is 30 days.
3445 The intervening values of have a fixed ratio of roughly 1.06914. The value
3446 oxFF is defined to mean a ticket has no expiration time. This should be
3447 used advisedly since individual servers may impose defacto upperbounds on
3448 ticket lifetimes. */
3450 #define TKTLIFENUMFIXED 64
3451 #define TKTLIFEMINFIXED 0x80
3452 #define TKTLIFEMAXFIXED 0xBF
3453 #define TKTLIFENOEXPIRE 0xFF
3454 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
3456 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3457 38400, /* 10.67 hours, 0.44 days */
3458 41055, /* 11.40 hours, 0.48 days */
3459 43894, /* 12.19 hours, 0.51 days */
3460 46929, /* 13.04 hours, 0.54 days */
3461 50174, /* 13.94 hours, 0.58 days */
3462 53643, /* 14.90 hours, 0.62 days */
3463 57352, /* 15.93 hours, 0.66 days */
3464 61318, /* 17.03 hours, 0.71 days */
3465 65558, /* 18.21 hours, 0.76 days */
3466 70091, /* 19.47 hours, 0.81 days */
3467 74937, /* 20.82 hours, 0.87 days */
3468 80119, /* 22.26 hours, 0.93 days */
3469 85658, /* 23.79 hours, 0.99 days */
3470 91581, /* 25.44 hours, 1.06 days */
3471 97914, /* 27.20 hours, 1.13 days */
3472 104684, /* 29.08 hours, 1.21 days */
3473 111922, /* 31.09 hours, 1.30 days */
3474 119661, /* 33.24 hours, 1.38 days */
3475 127935, /* 35.54 hours, 1.48 days */
3476 136781, /* 37.99 hours, 1.58 days */
3477 146239, /* 40.62 hours, 1.69 days */
3478 156350, /* 43.43 hours, 1.81 days */
3479 167161, /* 46.43 hours, 1.93 days */
3480 178720, /* 49.64 hours, 2.07 days */
3481 191077, /* 53.08 hours, 2.21 days */
3482 204289, /* 56.75 hours, 2.36 days */
3483 218415, /* 60.67 hours, 2.53 days */
3484 233517, /* 64.87 hours, 2.70 days */
3485 249664, /* 69.35 hours, 2.89 days */
3486 266926, /* 74.15 hours, 3.09 days */
3487 285383, /* 79.27 hours, 3.30 days */
3488 305116, /* 84.75 hours, 3.53 days */
3489 326213, /* 90.61 hours, 3.78 days */
3490 348769, /* 96.88 hours, 4.04 days */
3491 372885, /* 103.58 hours, 4.32 days */
3492 398668, /* 110.74 hours, 4.61 days */
3493 426234, /* 118.40 hours, 4.93 days */
3494 455705, /* 126.58 hours, 5.27 days */
3495 487215, /* 135.34 hours, 5.64 days */
3496 520904, /* 144.70 hours, 6.03 days */
3497 556921, /* 154.70 hours, 6.45 days */
3498 595430, /* 165.40 hours, 6.89 days */
3499 636601, /* 176.83 hours, 7.37 days */
3500 680618, /* 189.06 hours, 7.88 days */
3501 727680, /* 202.13 hours, 8.42 days */
3502 777995, /* 216.11 hours, 9.00 days */
3503 831789, /* 231.05 hours, 9.63 days */
3504 889303, /* 247.03 hours, 10.29 days */
3505 950794, /* 264.11 hours, 11.00 days */
3506 1016537, /* 282.37 hours, 11.77 days */
3507 1086825, /* 301.90 hours, 12.58 days */
3508 1161973, /* 322.77 hours, 13.45 days */
3509 1242318, /* 345.09 hours, 14.38 days */
3510 1328218, /* 368.95 hours, 15.37 days */
3511 1420057, /* 394.46 hours, 16.44 days */
3512 1518247, /* 421.74 hours, 17.57 days */
3513 1623226, /* 450.90 hours, 18.79 days */
3514 1735464, /* 482.07 hours, 20.09 days */
3515 1855462, /* 515.41 hours, 21.48 days */
3516 1983758, /* 551.04 hours, 22.96 days */
3517 2120925, /* 589.15 hours, 24.55 days */
3518 2267576, /* 629.88 hours, 26.25 days */
3519 2424367, /* 673.44 hours, 28.06 days */
3521 }; /* 720.00 hours, 30.00 days */
3523 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3524 * returns the corresponding end time. There are four simple cases to be
3525 * handled. The first is a life of 0xff, meaning no expiration, and results in
3526 * an end time of 0xffffffff. The second is when life is less than the values
3527 * covered by the table. In this case, the end time is the start time plus the
3528 * number of 5 minute intervals specified by life. The third case returns
3529 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
3530 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3531 * table to extract the lifetime in seconds, which is added to start to produce
3535 life_to_time(afs_uint32 start, unsigned char life)
3539 if (life == TKTLIFENOEXPIRE)
3541 if (life < TKTLIFEMINFIXED)
3542 return start + life * 5 * 60;
3543 if (life > TKTLIFEMAXFIXED)
3544 return start + MAXTKTLIFETIME;
3545 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3546 return start + realLife;
3549 /* time_to_life - takes start and end times for the ticket and returns a
3550 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3551 * lifetimes above 127*5minutes. First, the special case of (end ==
3552 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
3553 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
3554 * less than the first table entry are handled by rounding the requested
3555 * lifetime *up* to the next 5 minute interval. The final step is to search
3556 * the table for the smallest entry *greater than or equal* to the requested
3557 * entry. The actual code is prepared to handle the case where the table is
3558 * unordered but that it an unnecessary frill. */
3560 static unsigned char
3561 time_to_life(afs_uint32 start, afs_uint32 end)
3563 int lifetime = end - start;
3567 if (end == NEVERDATE)
3568 return TKTLIFENOEXPIRE;
3569 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
3571 if (lifetime < tkt_lifetimes[0])
3572 return (lifetime + 5 * 60 - 1) / (5 * 60);
3574 best = MAXKTCTICKETLIFETIME;
3575 for (i = 0; i < TKTLIFENUMFIXED; i++)
3576 if (tkt_lifetimes[i] >= lifetime) {
3577 int diff = tkt_lifetimes[i] - lifetime;
3585 return best_i + TKTLIFEMINFIXED;
3588 DWORD KFW_get_default_mslsa_import(krb5_context context)
3590 static const char * lsh_settings_key = "";
3591 static const char * lsh_mslsa_value = "";
3597 rc = RegOpenKeyEx(HKEY_CURRENT_USER, lsh_settings_key, 0, KEY_QUERY_VALUE, &hKey);
3601 dwCount = sizeof(DWORD);
3602 rc = RegQueryValueEx(hKey, lsh_mslsa_value, 0, 0, (LPBYTE) &import, &dwCount);
3608 rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lsh_settings_key, 0, KEY_QUERY_VALUE, &hKey);
3612 dwCount = sizeof(DWORD);
3613 rc = RegQueryValueEx(hKey, lsh_mslsa_value, 0, 0, (LPBYTE) &import, &dwCount);
3619 DWORD KFW_get_default_lifetime(krb5_context context, const char * realm)
3621 static const char * lifetime_val_name = "ticket_lifetime";
3624 krb5_appdefault_time(context, "aklog", realm, lifetime_val_name, 0, &t);
3627 t = krb5_config_get_time_default(context, NULL, 0,
3628 "realms", realm, lifetime_val_name, NULL);
3631 t = krb5_config_get_time_default(context, NULL, 0,
3632 "libdefaults", lifetime_val_name, NULL);