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_enable_DES(NULL);
166 KFW_import_windows_lsa();
167 #endif /* USE_MS2MIT */
168 KFW_import_ccache_data();
169 KFW_AFS_renew_expiring_tokens();
171 /* WIN32 NOTE: no way to get max chars */
172 if (!cm_GetRootCellName(rootcell))
173 KFW_AFS_renew_token_for_cell(rootcell);
176 ReleaseMutex(hMutex);
179 initialize_KTC_error_table();
180 initialize_PT_error_table();
189 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
192 static int init = TRUE;
193 static int bIsWow64 = FALSE;
197 LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
199 hModule = GetModuleHandle(TEXT("kernel32"));
201 fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process");
203 if (NULL != fnIsWow64Process)
205 if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
207 // on error, assume FALSE.
208 // in other words, do nothing.
211 FreeLibrary(hModule);
219 KFW_accept_dotted_usernames(void)
225 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
226 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
227 if (code == ERROR_SUCCESS) {
229 code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
230 (BYTE *) &value, &len);
231 RegCloseKey(parmKey);
233 if (code != ERROR_SUCCESS) {
234 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
235 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
236 if (code == ERROR_SUCCESS) {
238 code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
239 (BYTE *) &value, &len);
240 RegCloseKey (parmKey);
254 KFW_is_available(void)
260 code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
261 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
262 if (code == ERROR_SUCCESS) {
263 len = sizeof(enableKFW);
264 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
265 (BYTE *) &enableKFW, &len);
266 RegCloseKey (parmKey);
269 if (code != ERROR_SUCCESS) {
270 code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
271 0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
272 if (code == ERROR_SUCCESS) {
273 len = sizeof(enableKFW);
274 code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
275 (BYTE *) &enableKFW, &len);
276 RegCloseKey (parmKey);
285 /* If this is non-zero, then some Kerberos library was loaded. */
286 return (krb5_init_context != NULL);
290 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
291 int FreeContextFlag, krb5_context * context,
296 int krb5Error = ((int)(rc & 255));
298 errText = krb5_get_error_message(*context, rc);
299 StringCbPrintf(message, sizeof(message),
300 "%s\n(Kerberos error %ld)\n\n%s failed",
304 krb5_free_error_message(*context, (char *)errText);
306 DebugPrintf("%s", message);
308 MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
312 if (FreeContextFlag == 1) {
314 if (context && *context != NULL) {
316 if (cache && *cache != NULL) {
317 krb5_cc_close(*context, *cache);
321 krb5_free_context(*context);
330 KFW_AFS_update_princ_ccache_data(krb5_context context, krb5_ccache cc, int lsa)
332 struct principal_ccache_data * next = princ_cc_data;
333 krb5_principal principal = 0;
335 const char * ccname = NULL;
336 const char * cctype = NULL;
337 char * ccfullname = NULL;
338 krb5_error_code code = 0;
339 krb5_error_code cc_code = 0;
346 if (context == 0 || cc == 0)
349 code = krb5_cc_get_principal(context, cc, &principal);
352 code = krb5_unparse_name(context, principal, &pname);
353 if ( code ) goto cleanup;
355 ccname = krb5_cc_get_name(context, cc);
356 if (!ccname) goto cleanup;
358 cctype = krb5_cc_get_type(context, cc);
359 if (!cctype) goto cleanup;
361 len = strlen(ccname) + strlen(cctype) + 2;
362 ccfullname = malloc(len);
363 if (!ccfullname) goto cleanup;
365 StringCbPrintf(ccfullname, len, "%s:%s", cctype, ccname);
367 // Search the existing list to see if we have a match
369 for ( ; next ; next = next->next ) {
370 if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccfullname) )
375 // If not, match add a new node to the beginning of the list and assign init it
377 next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
378 next->next = princ_cc_data;
379 princ_cc_data = next;
380 next->principal = _strdup(pname);
381 next->ccache_name = ccfullname;
383 next->from_lsa = lsa;
385 next->expiration_time = 0;
389 flags = 0; // turn off OPENCLOSE mode
390 code = krb5_cc_set_flags(context, cc, flags);
391 if ( code ) goto cleanup;
393 code = krb5_timeofday(context, &now);
395 cc_code = krb5_cc_start_seq_get(context, cc, &cur);
397 while (!(cc_code = krb5_cc_next_cred(context, cc, &cur, &creds))) {
398 if ( creds.flags.b.initial) {
400 // we found the ticket we are looking for
401 // check validity of timestamp
402 // We add a 5 minutes fudge factor to compensate for potential
403 // clock skew errors between the KDC and client OS
405 valid = ((creds.times.starttime > 0) &&
406 now >= (creds.times.starttime - 300) &&
407 now < (creds.times.endtime + 300) &&
408 !creds.flags.b.invalid);
410 if ( next->from_lsa) {
412 next->expiration_time = creds.times.endtime;
414 } else if ( valid ) {
416 next->expiration_time = creds.times.endtime;
417 next->renew = (creds.times.renew_till > creds.times.endtime) &&
418 creds.flags.b.renewable;
421 next->expiration_time = 0;
425 krb5_free_cred_contents(context, &creds);
426 cc_code = KRB5_CC_END;
429 krb5_free_cred_contents(context, &creds);
432 if (cc_code == KRB5_CC_END) {
433 code = krb5_cc_end_seq_get(context, cc, &cur);
434 if (code) goto cleanup;
438 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
439 code = krb5_cc_set_flags(context, cc, flags);
444 krb5_free_unparsed_name(context,pname);
446 krb5_free_principal(context,principal);
450 KFW_AFS_find_ccache_for_principal(krb5_context context, char * principal,
451 char **ccache, int valid_only)
453 struct principal_ccache_data * next = princ_cc_data;
454 char * response = NULL;
456 if ( !principal || !ccache )
460 if ( (!valid_only || !next->expired) && !strcmp(next->principal, principal) ) {
462 // we always want to prefer the MS Kerberos LSA cache or
463 // the cache afscreds created specifically for the principal
464 // if the current entry is either one, drop the previous find
465 if ( next->from_lsa || !strcmp(next->ccache_name, principal) )
468 response = _strdup(next->ccache_name);
469 // MS Kerberos LSA is our best option so use it and quit
470 if ( next->from_lsa )
484 KFW_AFS_delete_princ_ccache_data(krb5_context context, char * pname, char * ccname)
486 struct principal_ccache_data ** next = &princ_cc_data;
488 if ( !pname && !ccname )
492 if ( !strcmp((*next)->principal,pname) ||
493 !strcmp((*next)->ccache_name,ccname) ) {
495 free((*next)->principal);
496 free((*next)->ccache_name);
498 (*next) = (*next)->next;
505 KFW_AFS_update_cell_princ_map(krb5_context context, char * cell, char *pname, int active)
507 struct cell_principal_map * next = cell_princ_map;
509 // Search the existing list to see if we have a match
511 for ( ; next ; next = next->next ) {
512 if ( !strcmp(next->cell, cell) ) {
513 if ( !strcmp(next->principal,pname) ) {
514 next->active = active;
517 // OpenAFS currently has a restriction of one active token per cell
518 // Therefore, whenever we update the table with a new active cell we
519 // must mark all of the other principal to cell entries as inactive.
527 // If not, match add a new node to the beginning of the list and assign init it
529 next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
530 next->next = cell_princ_map;
531 cell_princ_map = next;
532 next->principal = _strdup(pname);
533 next->cell = _strdup(cell);
534 next->active = active;
539 KFW_AFS_delete_cell_princ_maps(krb5_context context, char * pname, char * cell)
541 struct cell_principal_map ** next = &cell_princ_map;
543 if ( !pname && !cell )
547 if ( !strcmp((*next)->principal,pname) ||
548 !strcmp((*next)->cell,cell) ) {
550 free((*next)->principal);
553 (*next) = (*next)->next;
559 // Returns (if possible) a principal which has been known in
560 // the past to have been used to obtain tokens for the specified
562 // TODO: Attempt to return one which has not yet expired by checking
563 // the principal/ccache data
565 KFW_AFS_find_principals_for_cell(krb5_context context, char * cell, char **principals[], int active_only)
567 struct cell_principal_map * next_map = cell_princ_map;
568 const char * princ = NULL;
575 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
578 next_map = next_map->next;
581 if ( !principals || !count )
584 *principals = (char **) malloc(sizeof(char *) * count);
585 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
587 if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
588 (*principals)[i++] = _strdup(next_map->principal);
595 KFW_AFS_find_cells_for_princ(krb5_context context, char * pname, char **cells[], int active_only)
598 struct cell_principal_map * next_map = cell_princ_map;
599 const char * princ = NULL;
605 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
608 next_map = next_map->next;
614 *cells = (char **) malloc(sizeof(char *) * count);
615 for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
617 if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
618 (*cells)[i++] = _strdup(next_map->cell);
625 escape_unsafe_principal_characters(const char * pname,
633 for (src = pname; *src != '\0'; ++len, ++src) {
634 if (*src == '\\' || *src == '#' || *src == '<' ||
635 *src == '>' || *src == ':' || *src == '"' ||
636 *src == '/' || *src == '|' || *src == '?' ||
643 *new_name = (char *) malloc(len);
645 if (*new_name == NULL)
648 for (src = pname, dest = *new_name; *src != '\0'; ++src) {
650 case '\\': *dest++ = '#'; *dest++ = 'b'; break;
652 case '#' : *dest++ = '#'; *dest++ = '#'; break;
654 case '<' : *dest++ = '#'; *dest++ = 'l'; break;
656 case '>' : *dest++ = '#'; *dest++ = 'g'; break;
658 case ':' : *dest++ = '#'; *dest++ = 'c'; break;
660 case '"' : *dest++ = '#'; *dest++ = 't'; break;
662 case '/' : *dest++ = '#'; *dest++ = 'f'; break;
664 case '|' : *dest++ = '#'; *dest++ = 'p'; break;
666 case '?' : *dest++ = '#'; *dest++ = 'q'; break;
668 case '*' : *dest++ = '#'; *dest++ = 'a'; break;
670 default: *dest++ = *src;
678 get_default_ccache_name_for_principal(krb5_context context, krb5_principal principal,
682 krb5_error_code code;
687 code = krb5_unparse_name(context, principal, &pname);
688 if (code) goto cleanup;
690 len = strlen(pname) + 5;
691 *cc_name = (char *) malloc(len);
693 StringCbPrintfA(*cc_name, len, "API:%s", pname, GetCurrentThreadId());
697 krb5_free_unparsed_name(context, pname);
703 is_default_ccache_for_principal(krb5_context context, krb5_principal principal,
706 const char * cc_name;
707 char * def_cc_name = NULL;
709 const char *bs_def_cc;
712 cc_name = krb5_cc_get_name(context, cc);
714 get_default_ccache_name_for_principal(context, principal, &def_cc_name);
716 is_default = (cc_name != NULL && def_cc_name != NULL &&
718 (bs_cc = strrchr(cc_name, '\\')) != NULL &&
720 (bs_def_cc = strrchr(def_cc_name, '\\')) != NULL &&
722 !strcmp(bs_cc, bs_def_cc));
730 /** Given a principal return an existing ccache or create one and return */
732 KFW_get_ccache(krb5_context alt_context, krb5_principal principal, krb5_ccache * cc)
734 krb5_context context = NULL;
736 char * ccname = NULL;
737 krb5_error_code code;
740 context = alt_context;
742 code = krb5_init_context(&context);
743 if (code) goto cleanup;
747 code = krb5_unparse_name(context, principal, &pname);
748 if (code) goto cleanup;
750 if ( !KFW_AFS_find_ccache_for_principal(context,pname,&ccname,TRUE) &&
751 !KFW_AFS_find_ccache_for_principal(context,pname,&ccname,FALSE)) {
753 get_default_ccache_name_for_principal(context, principal, &ccname);
755 code = krb5_cc_resolve(context, ccname, cc);
757 code = krb5_cc_default(context, cc);
758 if (code) goto cleanup;
765 krb5_free_unparsed_name(context,pname);
766 if (context && (context != alt_context))
767 krb5_free_context(context);
773 // Import Microsoft Credentials into a new MIT ccache
775 KFW_import_windows_lsa(void)
777 krb5_context context = NULL;
778 krb5_ccache cc = NULL;
779 krb5_principal princ = NULL;
781 const char * princ_realm;
782 krb5_error_code code;
783 char cell[128]="", realm[128]="", *def_realm = 0;
784 DWORD dwMsLsaImport = 1;
786 code = krb5_init_context(&context);
787 if (code) goto cleanup;
789 code = krb5_cc_resolve(context, LSA_CCNAME, &cc);
790 if (code) goto cleanup;
792 KFW_AFS_update_princ_ccache_data(context, cc, TRUE);
794 code = krb5_cc_get_principal(context, cc, &princ);
795 if ( code ) goto cleanup;
797 dwMsLsaImport = KFW_get_default_mslsa_import(context);
798 switch ( dwMsLsaImport ) {
799 case 0: /* do not import */
801 case 1: /* always import */
803 case 2: { /* matching realm */
804 const char *ms_realm;
806 ms_realm = krb5_principal_get_realm(context, princ);
808 if (code = krb5_get_default_realm(context, &def_realm))
811 if (strcmp(def_realm, ms_realm))
819 code = krb5_unparse_name(context,princ,&pname);
820 if ( code ) goto cleanup;
822 princ_realm = krb5_principal_get_realm(context, princ);
823 StringCchCopyA(realm, sizeof(realm), princ_realm);
824 StringCchCopyA(cell, sizeof(cell), princ_realm);
827 code = KFW_AFS_klog(context, cc, "afs", cell, realm,
828 KFW_get_default_lifetime(context, realm), NULL);
830 DebugPrintf("KFW_AFS_klog() returns: %d\n", code);
832 if ( code ) goto cleanup;
834 KFW_AFS_update_cell_princ_map(context, cell, pname, TRUE);
838 krb5_free_unparsed_name(context,pname);
840 krb5_free_principal(context,princ);
842 krb5_free_default_realm(context, def_realm);
844 krb5_cc_close(context,cc);
846 krb5_free_context(context);
848 #endif /* USE_MS2MIT */
851 get_canonical_ccache(krb5_context context, krb5_ccache * pcc)
853 krb5_error_code code;
854 krb5_ccache cc = *pcc;
855 krb5_principal principal = 0;
857 code = krb5_cc_get_principal(context, cc, &principal);
861 if ( !is_default_ccache_for_principal(context, principal, cc)
862 && strcmp(krb5_cc_get_type(context, cc), LSA_CCTYPE) != 0) {
864 char * def_cc_name = NULL;
865 krb5_ccache def_cc = 0;
866 krb5_principal def_cc_princ = 0;
869 get_default_ccache_name_for_principal(context, principal, &def_cc_name);
871 code = krb5_cc_resolve(context, def_cc_name, &def_cc);
874 code = krb5_cc_get_principal(context, def_cc, &def_cc_princ);
875 if (code || !krb5_principal_compare(context, def_cc_princ, principal)) {
876 /* def_cc either doesn't exist or is home to an
879 DebugPrintf("Copying ccache [%s:%s]->[%s:%s]",
880 krb5_cc_get_type(context, cc), krb5_cc_get_name(context, cc),
881 krb5_cc_get_type(context, def_cc),
882 krb5_cc_get_name(context, def_cc));
884 code = krb5_cc_initialize(context, def_cc, principal);
887 code = krb5_cc_copy_creds(context, cc, def_cc);
889 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
893 code = krb5_cc_close(context, cc);
901 krb5_cc_close(context, def_cc);
904 krb5_free_principal(context, def_cc_princ);
911 krb5_free_principal(context, principal);
913 if (code == 0 && cc != 0) {
922 static krb5_error_code
923 check_and_get_tokens_for_ccache(krb5_context context, krb5_ccache cc)
925 krb5_error_code code = 0;
926 krb5_error_code cc_code = 0;
929 char * principal_name = NULL;
932 krb5_principal principal = 0;
933 code = krb5_cc_get_principal(context, cc, &principal);
936 code = krb5_unparse_name(context, principal, &principal_name);
939 krb5_free_principal(context, principal);
944 krb5_free_unparsed_name(context, principal_name);
948 cc_code = krb5_cc_start_seq_get(context, cc, &cur);
950 while (!(cc_code = krb5_cc_next_cred(context, cc, &cur, &creds))) {
952 const char * sname = krb5_principal_get_comp_string(context, creds.server, 0);
953 const char * cell = krb5_principal_get_comp_string(context, creds.server, 1);
954 const char * realm = krb5_principal_get_realm(context, creds.server);
956 if ( sname && cell && !strcmp("afs",sname) ) {
958 struct ktc_principal aserver;
959 struct ktc_principal aclient;
960 struct ktc_token atoken;
963 DebugPrintf("Found AFS ticket: %s%s%s@%s\n",
964 sname, (cell ? "/":""), (cell? cell : ""), realm);
966 memset(&aserver, '\0', sizeof(aserver));
967 StringCbCopy(aserver.name, sizeof(aserver.name), sname);
968 StringCbCopy(aserver.cell, sizeof(aserver.cell), cell);
970 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
972 // Found a token in AFS Client Server which matches
974 char pname[128], *p, *q;
976 for ( p=pname, q=aclient.name; *q; p++, q++)
979 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
984 DebugPrintf("Found AFS token: %s\n", pname);
986 if (strcmp(pname, principal_name) != 0)
989 KFW_AFS_update_cell_princ_map(context, cell, principal_name, active);
992 // Attempt to import it
994 KFW_AFS_update_cell_princ_map(context, cell, principal_name, active);
996 DebugPrintf("Calling KFW_AFS_klog() to obtain token\n");
998 code = KFW_AFS_klog(context, cc, "afs", cell, realm,
999 KFW_get_default_lifetime(context, realm), NULL);
1001 DebugPrintf("KFW_AFS_klog() returns: %d\n", code);
1006 DebugPrintf("Found ticket: %s%s%s@%s\n", sname,
1007 (cell? "/":""), (cell? cell:""), realm);
1010 krb5_free_cred_contents(context, &creds);
1013 if (cc_code == KRB5_CC_END) {
1014 cc_code = krb5_cc_end_seq_get(context, cc, &cur);
1020 // If there are existing MIT credentials, copy them to a new
1021 // ccache named after the principal
1023 // Enumerate all existing MIT ccaches and construct entries
1024 // in the principal_ccache table
1026 // Enumerate all existing AFS Tokens and construct entries
1027 // in the cell_principal table
1029 KFW_import_ccache_data(void)
1031 krb5_context context = NULL;
1033 krb5_error_code code;
1034 krb5_cccol_cursor cccol_cur;
1037 if ( IsDebuggerPresent() )
1038 OutputDebugString("KFW_import_ccache_data()\n");
1040 code = krb5_init_context(&context);
1041 if (code) goto cleanup;
1043 code = krb5_cccol_cursor_new(context, &cccol_cur);
1044 if (code) goto cleanup;
1046 while ((code = krb5_cccol_cursor_next(context, cccol_cur, &cc)) == 0 && cc != NULL) {
1048 if (!get_canonical_ccache(context, &cc)) {
1050 krb5_cc_close(context, cc);
1054 /* Turn off OPENCLOSE mode */
1055 code = krb5_cc_set_flags(context, cc, 0);
1056 if ( code ) goto cleanup;
1058 KFW_AFS_update_princ_ccache_data(context, cc,
1059 !strcmp(krb5_cc_get_type(context, cc),
1062 check_and_get_tokens_for_ccache(context, cc);
1064 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1065 code = krb5_cc_set_flags(context, cc, flags);
1068 krb5_cc_close(context,cc);
1073 krb5_cccol_cursor_free(context, &cccol_cur);
1077 krb5_free_context(context);
1081 KFW_enable_DES(krb5_context alt_context)
1083 krb5_context context;
1084 krb5_error_code code;
1086 if ( alt_context ) {
1087 context = alt_context;
1089 code = krb5_init_context(&context);
1090 if (code) goto cleanup;
1093 if (krb5_enctype_valid(context, ETYPE_DES_CBC_CRC))
1094 krb5_enctype_enable(context, ETYPE_DES_CBC_CRC);
1097 if (context && (context != alt_context))
1098 krb5_free_context(context);
1103 KFW_AFS_get_cred( char * username,
1110 static char reason[1024]="";
1111 krb5_context context = NULL;
1112 krb5_ccache cc = NULL;
1113 char * realm = NULL, * userrealm = NULL;
1114 krb5_principal principal = NULL;
1115 char * pname = NULL;
1116 krb5_error_code code;
1117 char local_cell[CELL_MAXNAMELEN+1];
1118 char **cells = NULL;
1120 struct afsconf_cell cellconfig;
1123 DebugPrintf("KFW_AFS_get_cred for token %s in cell %s\n", username, cell);
1125 memset(&cellconfig, 0, sizeof(cellconfig));
1127 code = krb5_init_context(&context);
1128 if ( code ) goto cleanup;
1130 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1131 if ( code ) goto cleanup;
1133 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1135 userrealm = strchr(username,'@');
1137 pname = strdup(username);
1138 if (!KFW_accept_dotted_usernames()) {
1139 userrealm = strchr(pname, '@');
1142 /* handle kerberos iv notation */
1143 while ( dot = strchr(pname,'.') ) {
1150 size_t len = strlen(username) + strlen(realm) + 2;
1151 pname = malloc(len);
1152 if (pname == NULL) {
1153 code = KRB5KRB_ERR_GENERIC;
1156 StringCbCopy(pname, len, username);
1158 if (!KFW_accept_dotted_usernames()) {
1159 /* handle kerberos iv notation */
1160 while ( dot = strchr(pname,'.') ) {
1164 StringCbCat( pname, len, "@");
1165 StringCbCat( pname, len, realm);
1167 if ( IsDebuggerPresent() ) {
1168 OutputDebugString("Realm of Cell: ");
1169 OutputDebugString(realm);
1170 OutputDebugString("\n");
1171 OutputDebugString("Realm of User: ");
1172 OutputDebugString(userrealm?userrealm:"<NULL>");
1173 OutputDebugString("\n");
1176 code = krb5_parse_name(context, pname, &principal);
1177 if ( code ) goto cleanup;
1179 code = KFW_get_ccache(context, principal, &cc);
1180 if ( code ) goto cleanup;
1182 if ( lifetime == 0 )
1183 lifetime = KFW_get_default_lifetime(context, realm);
1185 if ( password && password[0] ) {
1186 code = KFW_kinit( context, cc, HWND_DESKTOP,
1191 0, /* forwardable */
1192 0, /* not proxiable */
1194 1, /* noaddresses */
1195 0 /* no public ip */
1197 pLeash_get_default_forwardable(),
1198 pLeash_get_default_proxiable(),
1199 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1200 pLeash_get_default_noaddresses(),
1201 pLeash_get_default_publicip()
1202 #endif /* USE_LEASH */
1205 if ( IsDebuggerPresent() ) {
1207 StringCbPrintf(message, sizeof(message), "KFW_kinit() returns: %d\n", code);
1208 OutputDebugString(message);
1210 if ( code ) goto cleanup;
1212 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;
1223 KFW_AFS_update_cell_princ_map(context, cell, pname, TRUE);
1225 // Attempt to obtain new tokens for other cells supported by the same
1227 cell_count = KFW_AFS_find_cells_for_princ(context, pname, &cells, TRUE);
1228 if ( cell_count > 1 ) {
1229 while ( cell_count-- ) {
1230 if ( strcmp(cells[cell_count],cell) ) {
1231 if ( IsDebuggerPresent() ) {
1233 StringCbPrintf(message, sizeof(message),
1234 "found another cell for the same principal: %s\n", cell);
1235 OutputDebugString(message);
1238 if (cellconfig.linkedCell) {
1239 free(cellconfig.linkedCell);
1240 cellconfig.linkedCell = NULL;
1242 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1243 if ( code ) continue;
1245 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1246 if ( IsDebuggerPresent() ) {
1247 OutputDebugString("Realm: ");
1248 OutputDebugString(realm);
1249 OutputDebugString("\n");
1252 code = KFW_AFS_klog(context, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1253 if ( IsDebuggerPresent() ) {
1255 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1256 OutputDebugString(message);
1259 free(cells[cell_count]);
1262 } else if ( cell_count == 1 ) {
1271 krb5_cc_close(context, cc);
1272 if ( cellconfig.linkedCell )
1273 free(cellconfig.linkedCell);
1275 if ( code && reasonP ) {
1276 const char *msg = krb5_get_error_message(context, code);
1277 StringCbCopyN( reason, sizeof(reason),
1278 msg, sizeof(reason) - 1);
1280 krb5_free_error_message(context, msg);
1286 KFW_AFS_destroy_tickets_for_cell(char * cell)
1288 krb5_context context = NULL;
1289 krb5_error_code code;
1291 char ** principals = NULL;
1293 DebugPrintf("KFW_AFS_destroy_tickets_for_cell: %s\n", cell);
1295 code = krb5_init_context(&context);
1296 if (code) context = 0;
1298 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, FALSE);
1300 krb5_principal princ = 0;
1304 int cell_count = KFW_AFS_find_cells_for_princ(context, principals[count], NULL, TRUE);
1305 if ( cell_count > 1 ) {
1306 // TODO - What we really should do here is verify whether or not any of the
1307 // other cells which use this principal to obtain its credentials actually
1308 // have valid tokens or not. If they are currently using these credentials
1309 // we will skip them. For the time being we assume that if there is an active
1310 // map in the table that they are actively being used.
1314 code = krb5_parse_name(context, principals[count], &princ);
1315 if (code) goto loop_cleanup;
1317 code = KFW_get_ccache(context, princ, &cc);
1318 if (code) goto loop_cleanup;
1320 code = krb5_cc_destroy(context, cc);
1325 krb5_cc_close(context, cc);
1329 krb5_free_principal(context, princ);
1333 KFW_AFS_update_cell_princ_map(context, cell, principals[count], FALSE);
1334 free(principals[count]);
1339 krb5_free_context(context);
1344 KFW_AFS_destroy_tickets_for_principal(char * user)
1346 krb5_context context = NULL;
1347 krb5_error_code code;
1349 char ** cells = NULL;
1350 krb5_principal princ = NULL;
1351 krb5_ccache cc = NULL;
1353 DebugPrintf("KFW_AFS_destroy_tickets_for_user: %s\n", user);
1355 code = krb5_init_context(&context);
1358 code = krb5_parse_name(context, user, &princ);
1359 if (code) goto loop_cleanup;
1361 code = KFW_get_ccache(context, princ, &cc);
1362 if (code) goto loop_cleanup;
1364 code = krb5_cc_destroy(context, cc);
1369 krb5_cc_close(context, cc);
1373 krb5_free_principal(context, princ);
1377 count = KFW_AFS_find_cells_for_princ(context, user, &cells, TRUE);
1380 KFW_AFS_update_cell_princ_map(context, cells[count], user, FALSE);
1387 krb5_free_context(context);
1393 KFW_AFS_renew_expiring_tokens(void)
1395 krb5_error_code code = 0;
1396 krb5_context context = NULL;
1397 krb5_ccache cc = NULL;
1399 struct principal_ccache_data * pcc_next = princ_cc_data;
1402 const char * realm = NULL;
1403 char local_cell[CELL_MAXNAMELEN+1]="";
1404 struct afsconf_cell cellconfig;
1406 if ( pcc_next == NULL ) // nothing to do
1409 if ( IsDebuggerPresent() ) {
1410 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1413 memset(&cellconfig, 0, sizeof(cellconfig));
1415 code = krb5_init_context(&context);
1416 if (code) goto cleanup;
1418 code = krb5_timeofday(context, &now);
1419 if (code) goto cleanup;
1421 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1422 if ( pcc_next->expired )
1425 if ( now >= (pcc_next->expiration_time) ) {
1426 if ( !pcc_next->from_lsa ) {
1427 pcc_next->expired = 1;
1432 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1433 code = krb5_cc_resolve(context, pcc_next->ccache_name, &cc);
1436 code = KFW_renew(context,cc);
1438 if ( code && pcc_next->from_lsa)
1440 #endif /* USE_MS2MIT */
1443 KFW_AFS_update_princ_ccache_data(context, cc, pcc_next->from_lsa);
1444 if (code) goto loop_cleanup;
1446 // Attempt to obtain new tokens for other cells supported by the same
1448 cell_count = KFW_AFS_find_cells_for_princ(context, pcc_next->principal, &cells, TRUE);
1449 if ( cell_count > 0 ) {
1450 while ( cell_count-- ) {
1451 if ( IsDebuggerPresent() ) {
1452 OutputDebugString("Cell: ");
1453 OutputDebugString(cells[cell_count]);
1454 OutputDebugString("\n");
1456 if (cellconfig.linkedCell) {
1457 free(cellconfig.linkedCell);
1458 cellconfig.linkedCell = NULL;
1460 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1461 if ( code ) continue;
1462 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1463 if ( IsDebuggerPresent() ) {
1464 OutputDebugString("Realm: ");
1465 OutputDebugString(realm);
1466 OutputDebugString("\n");
1468 code = KFW_AFS_klog(context, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1469 if ( IsDebuggerPresent() ) {
1471 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1472 OutputDebugString(message);
1474 free(cells[cell_count]);
1482 krb5_cc_close(context,cc);
1489 krb5_cc_close(context,cc);
1491 krb5_free_context(context);
1492 if (cellconfig.linkedCell)
1493 free(cellconfig.linkedCell);
1500 KFW_AFS_renew_token_for_cell(char * cell)
1502 krb5_error_code code = 0;
1503 krb5_context context = NULL;
1505 char ** principals = NULL;
1507 if ( IsDebuggerPresent() ) {
1508 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1509 OutputDebugString(cell);
1510 OutputDebugString("\n");
1513 code = krb5_init_context(&context);
1514 if (code) goto cleanup;
1516 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, TRUE);
1518 // We know we must have a credential somewhere since we are
1519 // trying to renew a token
1521 KFW_import_ccache_data();
1522 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, TRUE);
1525 krb5_principal princ = 0;
1526 krb5_principal service = 0;
1528 krb5_creds mcreds, creds;
1529 #endif /* COMMENT */
1531 const char * realm = NULL;
1532 struct afsconf_cell cellconfig;
1533 char local_cell[CELL_MAXNAMELEN+1];
1535 memset(&cellconfig, 0, sizeof(cellconfig));
1538 code = krb5_parse_name(context, principals[count], &princ);
1539 if (code) goto loop_cleanup;
1541 code = KFW_get_ccache(context, princ, &cc);
1542 if (code) goto loop_cleanup;
1544 if (cellconfig.linkedCell) {
1545 free(cellconfig.linkedCell);
1546 cellconfig.linkedCell = NULL;
1548 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1549 if ( code ) goto loop_cleanup;
1551 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1552 if ( IsDebuggerPresent() ) {
1553 OutputDebugString("Realm: ");
1554 OutputDebugString(realm);
1555 OutputDebugString("\n");
1559 /* krb5_cc_remove_cred() is not implemented
1562 code = krb5_build_principal(context, &service, strlen(realm),
1563 realm, "afs", cell, NULL);
1565 memset(&mcreds, 0, sizeof(krb5_creds));
1566 mcreds.client = princ;
1567 mcreds.server = service;
1569 code = krb5_cc_retrieve_cred(context, cc, 0, &mcreds, &creds);
1571 if ( IsDebuggerPresent() ) {
1572 char * cname, *sname;
1573 krb5_unparse_name(context, creds.client, &cname);
1574 krb5_unparse_name(context, creds.server, &sname);
1575 OutputDebugString("Removing credential for client \"");
1576 OutputDebugString(cname);
1577 OutputDebugString("\" and service \"");
1578 OutputDebugString(sname);
1579 OutputDebugString("\"\n");
1580 krb5_free_unparsed_name(context,cname);
1581 krb5_free_unparsed_name(context,sname);
1584 code = krb5_cc_remove_cred(context, cc, 0, &creds);
1585 krb5_free_principal(context, creds.client);
1586 krb5_free_principal(context, creds.server);
1589 #endif /* COMMENT */
1591 code = KFW_AFS_klog(context, cc, "afs", cell, (char *)realm, 0,NULL);
1592 if ( IsDebuggerPresent() ) {
1594 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1595 OutputDebugString(message);
1600 krb5_cc_close(context, cc);
1604 krb5_free_principal(context, princ);
1608 krb5_free_principal(context, service);
1611 if (cellconfig.linkedCell) {
1612 free(cellconfig.linkedCell);
1613 cellconfig.linkedCell = NULL;
1616 KFW_AFS_update_cell_princ_map(context, cell, principals[count], code ? FALSE : TRUE);
1617 free(principals[count]);
1621 code = -1; // we did not renew the tokens
1625 krb5_free_context(context);
1626 return (code ? FALSE : TRUE);
1631 KFW_AFS_renew_tokens_for_all_cells(void)
1633 struct cell_principal_map * next = cell_princ_map;
1635 DebugPrintf("KFW_AFS_renew_tokens_for_all()\n");
1640 for ( ; next ; next = next->next ) {
1642 KFW_AFS_renew_token_for_cell(next->cell);
1648 KFW_renew(krb5_context alt_context, krb5_ccache alt_cc)
1650 krb5_error_code code = 0;
1651 krb5_context context = NULL;
1652 krb5_ccache cc = NULL;
1653 krb5_principal me = NULL;
1654 krb5_principal server = NULL;
1655 krb5_creds my_creds;
1656 const char *realm = NULL;
1658 memset(&my_creds, 0, sizeof(krb5_creds));
1660 if ( alt_context ) {
1661 context = alt_context;
1663 code = krb5_init_context(&context);
1664 if (code) goto cleanup;
1670 code = krb5_cc_default(context, &cc);
1671 if (code) goto cleanup;
1674 code = krb5_cc_get_principal(context, cc, &me);
1675 if (code) goto cleanup;
1677 realm = krb5_principal_get_realm(context, me);
1679 code = krb5_make_principal(context, &server, realm,
1680 KRB5_TGS_NAME, realm, NULL);
1684 if ( IsDebuggerPresent() ) {
1685 char * cname, *sname;
1686 krb5_unparse_name(context, me, &cname);
1687 krb5_unparse_name(context, server, &sname);
1688 DebugPrintf("Renewing credential for client \"%s\" and service\"%s\"\n",
1690 krb5_free_unparsed_name(context,cname);
1691 krb5_free_unparsed_name(context,sname);
1694 my_creds.client = me;
1695 my_creds.server = server;
1697 code = krb5_get_renewed_creds(context, &my_creds, me, cc, NULL);
1699 DebugPrintf("krb5_get_renewed_creds() failed: %d\n", code);
1703 code = krb5_cc_initialize(context, cc, me);
1705 DebugPrintf("krb5_cc_initialize() failed: %d\n", code);
1709 code = krb5_cc_store_cred(context, cc, &my_creds);
1711 DebugPrintf("krb5_cc_store_cred() failed: %d\n", code);
1716 if (my_creds.client == me)
1717 my_creds.client = 0;
1718 if (my_creds.server == server)
1719 my_creds.server = 0;
1720 krb5_free_cred_contents(context, &my_creds);
1722 krb5_free_principal(context, me);
1724 krb5_free_principal(context, server);
1725 if (cc && (cc != alt_cc))
1726 krb5_cc_close(context, cc);
1727 if (context && (context != alt_context))
1728 krb5_free_context(context);
1733 KFW_kinit( krb5_context alt_context,
1736 char *principal_name,
1738 krb5_deltat lifetime,
1741 krb5_deltat renew_life,
1745 krb5_error_code code = 0;
1746 krb5_context context = NULL;
1747 krb5_ccache cc = NULL;
1748 krb5_principal me = NULL;
1750 krb5_creds my_creds;
1751 krb5_get_init_creds_opt *options = NULL;
1752 krb5_addresses addrs = {0, NULL};
1753 int i = 0, addr_count = 0;
1755 memset(&my_creds, 0, sizeof(my_creds));
1758 context = alt_context;
1760 code = krb5_init_context(&context);
1761 if (code) goto cleanup;
1767 code = krb5_cc_default(context, &cc);
1768 if (code) goto cleanup;
1771 code = krb5_get_init_creds_opt_alloc(context, &options);
1772 if (code) goto cleanup;
1774 code = krb5_parse_name(context, principal_name, &me);
1775 if (code) goto cleanup;
1777 code = krb5_unparse_name(context, me, &name);
1778 if (code) goto cleanup;
1781 lifetime = KFW_get_default_lifetime(context,
1782 krb5_principal_get_realm(context, me));
1790 krb5_get_init_creds_opt_set_tkt_life(options, lifetime);
1791 krb5_get_init_creds_opt_set_forwardable(options, forwardable ? 1 : 0);
1792 krb5_get_init_creds_opt_set_proxiable(options, proxiable ? 1 : 0);
1793 krb5_get_init_creds_opt_set_renew_life(options, renew_life);
1795 krb5_get_init_creds_opt_set_addressless(context, options, TRUE);
1798 // we are going to add the public IP address specified by the user
1799 // to the list provided by the operating system
1800 struct sockaddr_in in_addr;
1802 krb5_addresses addr_l;
1804 krb5_get_all_client_addrs(context, &addrs);
1806 in_addr.sin_family = AF_INET;
1807 in_addr.sin_port = 0;
1808 in_addr.sin_addr.S_un.S_addr = htonl(publicIP);
1810 code = krb5_sockaddr2address(context, (struct sockaddr *)&in_addr,
1817 code = krb5_append_addresses(context, &addrs, &addr_l);
1819 krb5_free_address(context, &addr);
1822 krb5_get_init_creds_opt_set_address_list(options, &addrs);
1826 code = krb5_get_init_creds_password(context,
1829 password, // password
1830 KRB5_prompter, // prompter
1831 hParent, // prompter data
1838 code = krb5_cc_initialize(context, cc, me);
1842 code = krb5_cc_store_cred(context, cc, &my_creds);
1847 if ( addrs.len > 0 )
1848 krb5_free_addresses(context, &addrs);
1850 if (my_creds.client == me)
1851 my_creds.client = 0;
1853 krb5_free_cred_contents(context, &my_creds);
1855 krb5_free_unparsed_name(context, name);
1857 krb5_free_principal(context, me);
1859 krb5_get_init_creds_opt_free(context, options);
1860 if (cc && (cc != alt_cc))
1861 krb5_cc_close(context, cc);
1862 if (context && (context != alt_context))
1863 krb5_free_context(context);
1869 KFW_kdestroy(krb5_context alt_context, krb5_ccache alt_cc)
1871 krb5_context context = NULL;
1872 krb5_ccache cc = NULL;
1873 krb5_error_code code;
1876 context = alt_context;
1878 code = krb5_init_context(&context);
1879 if (code) goto cleanup;
1885 code = krb5_cc_default(context, &cc);
1886 if (code) goto cleanup;
1889 code = krb5_cc_destroy(context, cc);
1890 if ( !code ) cc = 0;
1893 if (cc && (cc != alt_cc))
1894 krb5_cc_close(context, cc);
1895 if (context && (context != alt_context))
1896 krb5_free_context(context);
1904 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1906 NTSTATUS Status = 0;
1908 TOKEN_STATISTICS Stats;
1914 *ppSessionData = NULL;
1916 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1920 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1921 CloseHandle( TokenHandle );
1925 Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1926 if ( FAILED(Status) || !ppSessionData )
1933 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
1934 // cache. It validates whether or not it is reasonable to assume that if we
1935 // attempted to retrieve valid tickets we could do so. Microsoft does not
1936 // automatically renew expired tickets. Therefore, the cache could contain
1937 // expired or invalid tickets. Microsoft also caches the user's password
1938 // and will use it to retrieve new TGTs if the cache is empty and tickets
1942 MSLSA_IsKerberosLogon(VOID)
1944 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
1945 BOOL Success = FALSE;
1947 if ( GetSecurityLogonSessionData(&pSessionData) ) {
1948 if ( pSessionData->AuthenticationPackage.Buffer ) {
1954 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
1955 usLength = (pSessionData->AuthenticationPackage).Length;
1958 StringCbCopyNW( buffer, sizeof(buffer)/sizeof(WCHAR),
1959 usBuffer, usLength);
1960 if ( !lstrcmpW(L"Kerberos",buffer) )
1964 LsaFreeReturnBuffer(pSessionData);
1968 #endif /* USE_MS2MIT */
1970 static BOOL CALLBACK
1971 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
1975 switch ( message ) {
1977 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
1979 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
1982 for ( i=0; i < mid_cnt ; i++ ) {
1983 if (mid_tb[i].echo == 0)
1984 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
1985 else if (mid_tb[i].echo == 2)
1986 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
1991 switch ( LOWORD(wParam) ) {
1993 for ( i=0; i < mid_cnt ; i++ ) {
1994 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
1995 *mid_tb[i].buf = '\0';
1999 EndDialog(hDialog, LOWORD(wParam));
2007 lpwAlign( LPWORD lpIn )
2011 ul = (ULONG_PTR) lpIn;
2015 return (LPWORD) ul;;
2019 * dialog widths are measured in 1/4 character widths
2020 * dialog height are measured in 1/8 character heights
2024 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2025 char * ptext[], int numlines, int width,
2026 int tb_cnt, struct textField * tb)
2030 LPDLGITEMTEMPLATE lpdit;
2036 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2043 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2045 // Define a dialog box.
2047 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2048 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2049 | DS_SETFOREGROUND | DS_3DLOOK
2050 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2051 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2054 lpdt->cx = 20 + width * 4;
2055 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2057 lpw = (LPWORD) (lpdt + 1);
2058 *lpw++ = 0; // no menu
2059 *lpw++ = 0; // predefined dialog box class (by default)
2061 lpwsz = (LPWSTR) lpw;
2062 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2064 *lpw++ = 8; // font size (points)
2065 lpwsz = (LPWSTR) lpw;
2066 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2070 //-----------------------
2071 // Define an OK button.
2072 //-----------------------
2073 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2074 lpdit = (LPDLGITEMTEMPLATE) lpw;
2075 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2076 lpdit->dwExtendedStyle = 0;
2077 lpdit->x = (lpdt->cx - 14)/4 - 20;
2078 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2081 lpdit->id = IDOK; // OK button identifier
2083 lpw = (LPWORD) (lpdit + 1);
2085 *lpw++ = 0x0080; // button class
2087 lpwsz = (LPWSTR) lpw;
2088 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2090 *lpw++ = 0; // no creation data
2092 //-----------------------
2093 // Define an Cancel button.
2094 //-----------------------
2095 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2096 lpdit = (LPDLGITEMTEMPLATE) lpw;
2097 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2098 lpdit->dwExtendedStyle = 0;
2099 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2100 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2103 lpdit->id = IDCANCEL; // CANCEL button identifier
2105 lpw = (LPWORD) (lpdit + 1);
2107 *lpw++ = 0x0080; // button class
2109 lpwsz = (LPWSTR) lpw;
2110 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2112 *lpw++ = 0; // no creation data
2114 /* Add controls for preface data */
2115 for ( i=0; i<numlines; i++) {
2116 /*-----------------------
2117 * Define a static text control.
2118 *-----------------------*/
2119 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2120 lpdit = (LPDLGITEMTEMPLATE) lpw;
2121 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2122 lpdit->dwExtendedStyle = 0;
2124 lpdit->y = 10 + i * 14;
2125 lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2127 lpdit->id = ID_TEXT + i; // text identifier
2129 lpw = (LPWORD) (lpdit + 1);
2131 *lpw++ = 0x0082; // static class
2133 lpwsz = (LPWSTR) lpw;
2134 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2135 -1, lpwsz, 2*width);
2137 *lpw++ = 0; // no creation data
2140 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2141 int len = (int)strlen(tb[i].label);
2146 for ( i=0; i<tb_cnt; i++) {
2148 /*-----------------------
2149 * Define a static text control.
2150 *-----------------------*/
2151 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2152 lpdit = (LPDLGITEMTEMPLATE) lpw;
2153 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2154 lpdit->dwExtendedStyle = 0;
2156 lpdit->y = 10 + (numlines + i + 1) * 14;
2157 lpdit->cx = pwid * 4;
2159 lpdit->id = ID_TEXT + numlines + i; // text identifier
2161 lpw = (LPWORD) (lpdit + 1);
2163 *lpw++ = 0x0082; // static class
2165 lpwsz = (LPWSTR) lpw;
2166 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2169 *lpw++ = 0; // no creation data
2171 /*-----------------------
2172 * Define an edit control.
2173 *-----------------------*/
2174 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2175 lpdit = (LPDLGITEMTEMPLATE) lpw;
2176 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2177 lpdit->dwExtendedStyle = 0;
2178 lpdit->x = 10 + (pwid + 1) * 4;
2179 lpdit->y = 10 + (numlines + i + 1) * 14;
2180 lpdit->cx = (width - (pwid + 1)) * 4;
2182 lpdit->id = ID_MID_TEXT + i; // identifier
2184 lpw = (LPWORD) (lpdit + 1);
2186 *lpw++ = 0x0081; // edit class
2188 lpwsz = (LPWSTR) lpw;
2189 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2192 *lpw++ = 0; // no creation data
2196 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2197 hwndOwner, (DLGPROC) MultiInputDialogProc);
2201 case 0: /* Timeout */
2209 StringCbPrintf(buf, sizeof(buf), "DialogBoxIndirect() failed: %d", GetLastError());
2210 MessageBox(hwndOwner,
2213 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2220 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2222 HINSTANCE hInst = 0;
2223 size_t maxwidth = 0;
2226 char * plines[16], *p = preface ? preface : "";
2229 for ( i=0; i<16; i++ )
2232 while (*p && numlines < 16) {
2233 plines[numlines++] = p;
2234 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2235 if ( *p == '\r' && *(p+1) == '\n' ) {
2238 } else if ( *p == '\n' ) {
2241 if ( strlen(plines[numlines-1]) > maxwidth )
2242 maxwidth = strlen(plines[numlines-1]);
2245 for ( i=0;i<n;i++ ) {
2246 len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2247 if ( maxwidth < len )
2251 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2254 static krb5_error_code KRB5_CALLCONV
2255 KRB5_prompter( krb5_context context,
2260 krb5_prompt prompts[])
2262 krb5_error_code errcode = 0;
2264 struct textField * tb = NULL;
2265 int len = 0, blen=0, nlen=0;
2266 HWND hParent = (HWND)data;
2269 nlen = (int)strlen(name)+2;
2272 blen = (int)strlen(banner)+2;
2274 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2277 memset(tb,0,sizeof(struct textField) * num_prompts);
2278 for ( i=0; i < num_prompts; i++ ) {
2279 tb[i].buf = prompts[i].reply->data;
2280 tb[i].len = prompts[i].reply->length;
2281 tb[i].label = prompts[i].prompt;
2283 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2286 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2288 for ( i=0; i < num_prompts; i++ )
2289 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2297 for (i = 0; i < num_prompts; i++) {
2298 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2305 KFW_AFS_wait_for_service_start(void)
2310 CurrentState = SERVICE_START_PENDING;
2311 memset(HostName, '\0', sizeof(HostName));
2312 gethostname(HostName, sizeof(HostName));
2314 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2316 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2318 if ( IsDebuggerPresent() ) {
2319 switch ( CurrentState ) {
2320 case SERVICE_STOPPED:
2321 OutputDebugString("SERVICE_STOPPED\n");
2323 case SERVICE_START_PENDING:
2324 OutputDebugString("SERVICE_START_PENDING\n");
2326 case SERVICE_STOP_PENDING:
2327 OutputDebugString("SERVICE_STOP_PENDING\n");
2329 case SERVICE_RUNNING:
2330 OutputDebugString("SERVICE_RUNNING\n");
2332 case SERVICE_CONTINUE_PENDING:
2333 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2335 case SERVICE_PAUSE_PENDING:
2336 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2338 case SERVICE_PAUSED:
2339 OutputDebugString("SERVICE_PAUSED\n");
2342 OutputDebugString("UNKNOWN Service State\n");
2345 if (CurrentState == SERVICE_STOPPED)
2347 if (CurrentState == SERVICE_RUNNING)
2363 memset(HostName, '\0', sizeof(HostName));
2364 gethostname(HostName, sizeof(HostName));
2365 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2367 if (CurrentState != SERVICE_RUNNING)
2370 rc = ktc_ForgetAllTokens();
2376 #define ALLOW_REGISTER 1
2378 ViceIDToUsername(char *username,
2379 char *realm_of_user,
2380 char *realm_of_cell,
2382 struct ktc_principal *aclient,
2383 struct ktc_principal *aserver,
2384 struct ktc_token *atoken)
2386 static char lastcell[CELL_MAXNAMELEN+1] = { 0 };
2387 static char confdir[512] = { 0 };
2388 #ifdef AFS_ID_TO_NAME
2389 char username_copy[BUFSIZ];
2390 #endif /* AFS_ID_TO_NAME */
2391 long viceId = ANONYMOUSID; /* AFS uid of user */
2393 #ifdef ALLOW_REGISTER
2395 #endif /* ALLOW_REGISTER */
2397 if (confdir[0] == '\0')
2398 cm_GetConfigDir(confdir, sizeof(confdir));
2400 StringCbCopyN( lastcell, sizeof(lastcell),
2401 aserver->cell, sizeof(lastcell) - 1);
2403 if (!pr_Initialize (0, confdir, aserver->cell)) {
2404 char sname[PR_MAXNAMELEN];
2405 StringCbCopyN( sname, sizeof(sname),
2406 username, sizeof(sname) - 1);
2407 status = pr_SNameToId (sname, &viceId);
2412 * This is a crock, but it is Transarc's crock, so
2413 * we have to play along in order to get the
2414 * functionality. The way the afs id is stored is
2415 * as a string in the username field of the token.
2416 * Contrary to what you may think by looking at
2417 * the code for tokens, this hack (AFS ID %d) will
2418 * not work if you change %d to something else.
2422 * This code is taken from cklog -- it lets people
2423 * automatically register with the ptserver in foreign cells
2426 #ifdef ALLOW_REGISTER
2428 if (viceId != ANONYMOUSID) {
2429 #else /* ALLOW_REGISTER */
2430 if ((status == 0) && (viceId != ANONYMOUSID))
2431 #endif /* ALLOW_REGISTER */
2433 #ifdef AFS_ID_TO_NAME
2434 StringCbCopyN( username_copy, sizeof(username_copy),
2435 username, sizeof(username_copy) - 1);
2436 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2437 #endif /* AFS_ID_TO_NAME */
2439 #ifdef ALLOW_REGISTER
2440 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2442 StringCbCopyN( aclient->name, sizeof(aclient->name),
2443 username, sizeof(aclient->name) - 1);
2444 aclient->instance[0] = '\0';
2445 StringCbCopyN( aclient->cell, sizeof(aclient->cell),
2446 realm_of_user, sizeof(aclient->cell) - 1);
2447 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2449 if (status = pr_Initialize(1L, confdir, aserver->cell))
2451 status = pr_CreateUser(username, &id);
2455 #ifdef AFS_ID_TO_NAME
2456 StringCbCopyN( username_copy, sizeof(username_copy),
2457 username, sizeof(username_copy) - 1);
2458 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2459 #endif /* AFS_ID_TO_NAME */
2462 #endif /* ALLOW_REGISTER */
2468 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
2473 ret = decode_Ticket(v5cred->ticket.data, v5cred->ticket.length,
2476 StringCbCopy(dest, destlen, ticket.realm);
2478 free_Ticket(&ticket);
2483 KFW_AFS_continue_aklog_processing_after_krb5_error(krb5_error_code code)
2485 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2486 code == KRB5_ERR_HOST_REALM_UNKNOWN ||
2487 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2488 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2497 krb5_context alt_context,
2502 int lifetime, /* unused parameter */
2507 struct ktc_principal aserver;
2508 struct ktc_principal aclient;
2509 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2510 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2511 char local_cell[CELL_MAXNAMELEN+1];
2512 char Dmycell[CELL_MAXNAMELEN+1];
2513 struct ktc_token atoken;
2514 struct ktc_token btoken;
2515 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2516 char RealmName[128];
2518 char ServiceName[128];
2521 krb5_context context = NULL;
2522 krb5_ccache cc = NULL;
2524 krb5_creds * k5creds = NULL;
2525 krb5_error_code code;
2526 krb5_principal client_principal = NULL;
2527 krb5_data * k5data = NULL;
2528 unsigned int retry = 0;
2531 memset(HostName, '\0', sizeof(HostName));
2532 gethostname(HostName, sizeof(HostName));
2533 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2534 if ( IsDebuggerPresent() )
2535 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2538 if (CurrentState != SERVICE_RUNNING) {
2539 if ( IsDebuggerPresent() )
2540 OutputDebugString("AFSD Service NOT RUNNING\n");
2544 memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
2545 memset(RealmName, '\0', sizeof(RealmName));
2546 memset(CellName, '\0', sizeof(CellName));
2547 memset(ServiceName, '\0', sizeof(ServiceName));
2548 memset(realm_of_user, '\0', sizeof(realm_of_user));
2549 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2550 if (cell && cell[0])
2551 StringCbCopyN( Dmycell, sizeof(Dmycell),
2552 cell, sizeof(Dmycell) - 1);
2554 memset(Dmycell, '\0', sizeof(Dmycell));
2556 // NULL or empty cell returns information on local cell
2557 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2559 // KFW_AFS_error(rc, "get_cellconfig()");
2563 if ( alt_context ) {
2564 context = alt_context;
2566 code = krb5_init_context(&context);
2567 if (code) goto cleanup;
2573 code = krb5_cc_default(context, &cc);
2578 memset(&increds, 0, sizeof(increds));
2580 code = krb5_cc_get_principal(context, cc, &client_principal);
2582 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2584 OutputDebugString("Principal Not Found for ccache\n");
2589 if (!KFW_accept_dotted_usernames()) {
2591 /* look for client principals which cannot be distinguished
2592 * from Kerberos 4 multi-component principal names
2594 comp = krb5_principal_get_comp_string(context,client_principal,0);
2595 if (strchr(comp, '.') != NULL) {
2596 OutputDebugString("Illegal Principal name contains dot in first component\n");
2597 rc = KRB5KRB_ERR_GENERIC;
2602 StringCbCopy(realm_of_user, sizeof(realm_of_user),
2603 krb5_principal_get_realm(context, client_principal));
2605 StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
2606 afs_realm_of_cell(context, &ak_cellconfig),
2607 sizeof(realm_of_cell) - 1);
2609 if (strlen(service) == 0)
2610 StringCbCopy( ServiceName, sizeof(ServiceName), "afs");
2612 StringCbCopyN( ServiceName, sizeof(ServiceName),
2613 service, sizeof(ServiceName) - 1);
2615 if (strlen(cell) == 0)
2616 StringCbCopyN( CellName, sizeof(CellName),
2617 local_cell, sizeof(CellName) - 1);
2619 StringCbCopyN( CellName, sizeof(CellName),
2620 cell, sizeof(CellName) - 1);
2622 if (strlen(realm) == 0)
2623 StringCbCopyN( RealmName, sizeof(RealmName),
2624 realm_of_cell, sizeof(RealmName) - 1);
2626 StringCbCopyN( RealmName, sizeof(RealmName),
2627 realm, sizeof(RealmName) - 1);
2629 code = KRB5KRB_ERR_GENERIC;
2631 increds.client = client_principal;
2632 increds.times.endtime = 0;
2633 /* Ask for DES since that is what V4 understands */
2634 increds.session.keytype = ENCTYPE_DES_CBC_CRC;
2636 /* ALWAYS first try service/cell@CLIENT_REALM */
2637 if (code = krb5_build_principal(context, &increds.server,
2638 (int)strlen(realm_of_user),
2647 if ( IsDebuggerPresent() ) {
2648 char * cname, *sname;
2649 krb5_unparse_name(context, increds.client, &cname);
2650 krb5_unparse_name(context, increds.server, &sname);
2651 OutputDebugString("Getting tickets for \"");
2652 OutputDebugString(cname);
2653 OutputDebugString("\" and service \"");
2654 OutputDebugString(sname);
2655 OutputDebugString("\"\n");
2656 krb5_free_unparsed_name(context,cname);
2657 krb5_free_unparsed_name(context,sname);
2660 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2663 * The client's realm is a local realm for the cell.
2664 * Save it so that later the pts registration will not
2667 StringCbCopyN(realm_of_cell, sizeof(realm_of_cell),
2668 realm_of_user, sizeof(realm_of_cell) - 1);
2671 if (KFW_AFS_continue_aklog_processing_after_krb5_error(code)) {
2672 if (strcmp(realm_of_user, RealmName)) {
2673 /* service/cell@REALM */
2675 code = krb5_build_principal(context, &increds.server,
2676 (int)strlen(RealmName),
2682 if ( IsDebuggerPresent() ) {
2683 char * cname, *sname;
2684 krb5_unparse_name(context, increds.client, &cname);
2685 krb5_unparse_name(context, increds.server, &sname);
2686 OutputDebugString("Getting tickets for \"");
2687 OutputDebugString(cname);
2688 OutputDebugString("\" and service \"");
2689 OutputDebugString(sname);
2690 OutputDebugString("\"\n");
2691 krb5_free_unparsed_name(context,cname);
2692 krb5_free_unparsed_name(context,sname);
2696 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2699 if (KFW_AFS_continue_aklog_processing_after_krb5_error(code)) {
2700 /* Or service@REALM */
2701 krb5_free_principal(context,increds.server);
2703 code = krb5_build_principal(context, &increds.server,
2704 (int)strlen(RealmName),
2709 if ( IsDebuggerPresent() ) {
2710 char * cname, *sname;
2711 krb5_unparse_name(context, increds.client, &cname);
2712 krb5_unparse_name(context, increds.server, &sname);
2713 DebugPrintf("Getting tickets for \"%s\" and service \"%s\"\n", cname, sname);
2714 krb5_free_unparsed_name(context,cname);
2715 krb5_free_unparsed_name(context,sname);
2719 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2724 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
2727 DebugPrintf("krb5_get_credentials returns: %d\n", code);
2731 /* This code inserts the entire K5 ticket into the token */
2732 memset(&aserver, '\0', sizeof(aserver));
2733 StringCbCopyN(aserver.name, sizeof(aserver.name),
2734 ServiceName, sizeof(aserver.name) - 1);
2735 StringCbCopyN(aserver.cell, sizeof(aserver.cell),
2736 CellName, sizeof(aserver.cell) - 1);
2738 memset(&atoken, '\0', sizeof(atoken));
2739 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2740 atoken.startTime = k5creds->times.starttime;
2741 atoken.endTime = k5creds->times.endtime;
2742 memcpy(&atoken.sessionKey,
2743 k5creds->session.keyvalue.data,
2744 k5creds->session.keyvalue.length);
2745 atoken.ticketLen = k5creds->ticket.length;
2746 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2749 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2750 if ( IsDebuggerPresent() ) {
2752 StringCbPrintf(message, sizeof(message), "ktc_GetToken returns: %d\n", rc);
2753 OutputDebugString(message);
2755 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2756 if ( rc == KTC_NOCM && retry < 20 ) {
2759 goto retry_gettoken5;
2764 if (atoken.kvno == btoken.kvno &&
2765 atoken.ticketLen == btoken.ticketLen &&
2766 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2767 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2769 /* Success - Nothing to do */
2773 // * Reset the "aclient" structure before we call ktc_SetToken.
2774 // * This structure was first set by the ktc_GetToken call when
2775 // * we were comparing whether identical tokens already existed.
2777 StringCbCopy(aclient.name, sizeof(aclient.name),
2778 krb5_principal_get_comp_string(context, k5creds->client, 0));
2780 if ( krb5_principal_get_num_comp(context, k5creds->client) > 1 ) {
2781 StringCbCat(aclient.name, sizeof(aclient.name), ".");
2782 StringCbCat(aclient.name, sizeof(aclient.name),
2783 krb5_principal_get_comp_string(context, k5creds->client, 1));
2785 aclient.instance[0] = '\0';
2787 StringCbCopyN(aclient.cell, sizeof(aclient.cell),
2788 realm_of_cell, sizeof(aclient.cell) - 1);
2790 /* For Khimaira, always append the realm name */
2791 StringCbCat(aclient.name, sizeof(aclient.name), "@");
2792 StringCbCat(aclient.name, sizeof(aclient.name),
2793 krb5_principal_get_realm(context, k5creds->client));
2795 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
2796 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
2797 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
2798 &aclient, &aserver, &atoken);
2801 StringCbCopyN(aclient.smbname, sizeof(aclient.smbname),
2802 smbname, sizeof(aclient.smbname) - 1);
2804 aclient.smbname[0] = '\0';
2806 if ( IsDebuggerPresent() ) {
2808 StringCbPrintf(message, sizeof(message), "aclient.name: %s\n", aclient.name);
2809 OutputDebugString(message);
2810 StringCbPrintf(message, sizeof(message), "aclient.smbname: %s\n", aclient.smbname);
2811 OutputDebugString(message);
2814 rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
2817 if (client_principal)
2818 krb5_free_principal(context,client_principal);
2819 /* increds.client == client_principal */
2821 krb5_free_principal(context,increds.server);
2822 if (cc && (cc != alt_cc))
2823 krb5_cc_close(context, cc);
2824 if (context && (context != alt_context))
2825 krb5_free_context(context);
2826 if (ak_cellconfig.linkedCell)
2827 free(ak_cellconfig.linkedCell);
2829 return(rc? rc : code);
2832 /**************************************/
2833 /* afs_realm_of_cell(): */
2834 /**************************************/
2836 afs_realm_of_cell(krb5_context context, struct afsconf_cell *cellconfig)
2838 static char krbrlm[REALM_SZ+1]="";
2839 char ** realmlist=NULL;
2845 r = krb5_get_host_realm(context, cellconfig->hostName[0], &realmlist);
2846 if ( !r && realmlist && realmlist[0] ) {
2847 StringCbCopyN( krbrlm, sizeof(krbrlm),
2848 realmlist[0], sizeof(krbrlm) - 1);
2849 krb5_free_host_realm(context, realmlist);
2855 char *t = cellconfig->name;
2860 if (islower(c)) c=toupper(c);
2868 /**************************************/
2869 /* KFW_AFS_get_cellconfig(): */
2870 /**************************************/
2872 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
2875 char newcell[CELL_MAXNAMELEN+1];
2876 char linkedcell[CELL_MAXNAMELEN+1]="";
2878 local_cell[0] = (char)0;
2879 memset(cellconfig, 0, sizeof(*cellconfig));
2881 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
2882 if (rc = cm_GetRootCellName(local_cell))
2887 if (strlen(cell) == 0)
2888 StringCbCopy(cell, CELL_MAXNAMELEN, local_cell);
2890 rc = cm_SearchCellRegistry(1, cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
2891 if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
2892 rc = cm_SearchCellFileEx(cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
2895 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
2899 StringCbCopyN( cellconfig->name, sizeof(cellconfig->name),
2900 newcell, sizeof(cellconfig->name) - 1);
2902 cellconfig->linkedCell = strdup(linkedcell);
2907 /**************************************/
2908 /* get_cellconfig_callback(): */
2909 /**************************************/
2911 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep, unsigned short ipRank)
2913 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
2915 cc->hostAddr[cc->numServers] = *addrp;
2916 StringCbCopyN( cc->hostName[cc->numServers], sizeof(cc->hostName[cc->numServers]),
2917 namep, sizeof(cc->hostName[cc->numServers]) - 1);
2923 /**************************************/
2924 /* KFW_AFS_error(): */
2925 /**************************************/
2927 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
2930 const char *errText;
2932 // Using AFS defines as error messages for now, until Transarc
2933 // gets back to me with "string" translations of each of these
2935 if (rc == KTC_ERROR)
2936 errText = "KTC_ERROR";
2937 else if (rc == KTC_TOOBIG)
2938 errText = "KTC_TOOBIG";
2939 else if (rc == KTC_INVAL)
2940 errText = "KTC_INVAL";
2941 else if (rc == KTC_NOENT)
2942 errText = "KTC_NOENT";
2943 else if (rc == KTC_PIOCTLFAIL)
2944 errText = "KTC_PIOCTLFAIL";
2945 else if (rc == KTC_NOPIOCTL)
2946 errText = "KTC_NOPIOCTL";
2947 else if (rc == KTC_NOCELL)
2948 errText = "KTC_NOCELL";
2949 else if (rc == KTC_NOCM)
2950 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
2952 errText = "Unknown error!";
2954 StringCbPrintf(message, sizeof(message), "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
2956 if ( IsDebuggerPresent() ) {
2957 OutputDebugString(message);
2958 OutputDebugString("\n");
2960 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
2966 LPSTR lpszMachineName,
2967 LPSTR lpszServiceName,
2968 DWORD *lpdwCurrentState)
2971 SC_HANDLE schSCManager = NULL;
2972 SC_HANDLE schService = NULL;
2973 DWORD fdwDesiredAccess = 0;
2974 SERVICE_STATUS ssServiceStatus = {0};
2977 *lpdwCurrentState = 0;
2979 fdwDesiredAccess = GENERIC_READ;
2981 schSCManager = OpenSCManager(lpszMachineName,
2985 if(schSCManager == NULL)
2987 hr = GetLastError();
2991 schService = OpenService(schSCManager,
2995 if(schService == NULL)
2997 hr = GetLastError();
3001 fRet = QueryServiceStatus(schService,
3006 hr = GetLastError();
3010 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3014 CloseServiceHandle(schService);
3015 CloseServiceHandle(schSCManager);
3020 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3022 krb5_context context = NULL;
3023 krb5_ccache cc = NULL;
3024 krb5_error_code code;
3026 const char * realm = NULL;
3027 krb5_principal principal = NULL;
3028 char * pname = NULL;
3029 char password[PROBE_PASSWORD_LEN+1];
3030 BOOL serverReachable = 0;
3032 code = krb5_init_context(&context);
3033 if (code) goto cleanup;
3036 realm = afs_realm_of_cell(context, cellconfig); // do not free
3038 code = krb5_build_principal(context, &principal, (int)strlen(realm),
3039 realm, PROBE_USERNAME, NULL, NULL);
3040 if ( code ) goto cleanup;
3042 code = KFW_get_ccache(context, principal, &cc);
3043 if ( code ) goto cleanup;
3045 code = krb5_unparse_name(context, principal, &pname);
3046 if ( code ) goto cleanup;
3048 pwdata.data = password;
3049 pwdata.length = PROBE_PASSWORD_LEN;
3050 krb5_c_random_make_octets(context, &pwdata);
3053 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3054 if (password[i] == '\0')
3057 password[PROBE_PASSWORD_LEN] = '\0';
3059 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3069 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3070 case KRB5KDC_ERR_CLIENT_REVOKED:
3071 case KRB5KDC_ERR_CLIENT_NOTYET:
3072 case KRB5KDC_ERR_PREAUTH_FAILED:
3073 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3074 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3075 serverReachable = TRUE;
3078 serverReachable = FALSE;
3083 krb5_free_unparsed_name(context,pname);
3085 krb5_free_principal(context,principal);
3087 krb5_cc_close(context,cc);
3089 krb5_free_context(context);
3091 return serverReachable;
3095 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3097 krb5_context context = NULL;
3098 krb5_error_code code;
3099 krb5_ccache mslsa_ccache=NULL;
3100 krb5_principal princ = NULL;
3101 char * pname = NULL;
3104 if (!KFW_is_available())
3107 if (code = krb5_init_context(&context))
3110 if (code = krb5_cc_resolve(context, "MSLSA:", &mslsa_ccache))
3113 if (code = krb5_cc_get_principal(context, mslsa_ccache, &princ))
3116 if (code = krb5_unparse_name(context, princ, &pname))
3119 if ( strlen(pname) < *dwSize ) {
3120 StringCbCopyN(szUser, *dwSize, pname, (*dwSize) - 1);
3123 *dwSize = (DWORD)strlen(pname);
3127 krb5_free_unparsed_name(context, pname);
3130 krb5_free_principal(context, princ);
3133 krb5_cc_close(context, mslsa_ccache);
3136 krb5_free_context(context);
3141 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3143 // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3144 PSID pSystemSID = NULL;
3145 DWORD SystemSIDlength = 0, UserSIDlength = 0;
3146 PACL ccacheACL = NULL;
3147 DWORD ccacheACLlength = 0;
3148 PTOKEN_USER pTokenUser = NULL;
3157 /* Get System SID */
3158 if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3164 SystemSIDlength = GetLengthSid(pSystemSID);
3165 ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3166 + SystemSIDlength - sizeof(DWORD);
3169 if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3171 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3172 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3174 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3179 UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3181 ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
3186 ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3191 InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3192 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3193 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3196 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3197 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3198 pTokenUser->User.Sid);
3199 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3200 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3205 gle = GetLastError();
3206 if (gle != ERROR_NO_TOKEN)
3209 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3210 OWNER_SECURITY_INFORMATION,
3211 pTokenUser->User.Sid,
3215 gle = GetLastError();
3216 if (gle != ERROR_NO_TOKEN)
3220 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3221 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3226 gle = GetLastError();
3227 if (gle != ERROR_NO_TOKEN)
3234 LocalFree(pSystemSID);
3236 LocalFree(pTokenUser);
3238 LocalFree(ccacheACL);
3243 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3246 DWORD dwSize = size-1; /* leave room for nul */
3249 if (!hUserToken || !newfilename || size <= 0)
3252 *newfilename = '\0';
3254 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3255 if ( !dwLen || dwLen > dwSize )
3256 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3257 if ( !dwLen || dwLen > dwSize )
3260 newfilename[dwSize] = '\0';
3265 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3267 char filename[MAX_PATH] = "";
3269 char cachename[MAX_PATH + 8] = "FILE:";
3270 krb5_context context = NULL;
3271 krb5_error_code code;
3272 krb5_principal princ = NULL;
3273 krb5_ccache cc = NULL;
3274 krb5_ccache ncc = NULL;
3276 if (!user || !szLogonId)
3279 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3280 if ( count > sizeof(filename) || count == 0 ) {
3281 GetWindowsDirectory(filename, sizeof(filename));
3284 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3287 StringCbCat( filename, sizeof(filename), "\\");
3288 StringCbCat( filename, sizeof(filename), szLogonId);
3290 StringCbCat( cachename, sizeof(cachename), filename);
3292 DeleteFile(filename);
3294 code = krb5_init_context(&context);
3295 if (code) goto cleanup;
3297 code = krb5_parse_name(context, user, &princ);
3298 if (code) goto cleanup;
3300 code = KFW_get_ccache(context, princ, &cc);
3301 if (code) goto cleanup;
3303 code = krb5_cc_resolve(context, cachename, &ncc);
3304 if (code) goto cleanup;
3306 code = krb5_cc_initialize(context, ncc, princ);
3307 if (code) goto cleanup;
3309 code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3310 if (code) goto cleanup;
3312 code = krb5_cc_copy_creds(context,cc,ncc);
3316 krb5_cc_close(context, cc);
3320 krb5_cc_close(context, ncc);
3324 krb5_free_principal(context, princ);
3329 krb5_free_context(context);
3333 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3335 char cachename[MAX_PATH + 8] = "FILE:";
3336 krb5_context context = NULL;
3337 krb5_error_code code;
3338 krb5_principal princ = NULL;
3339 krb5_ccache cc = NULL;
3340 krb5_ccache ncc = NULL;
3346 if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3349 code = krb5_init_context(&context);
3352 StringCbCat( cachename, sizeof(cachename), filename);
3354 code = krb5_cc_resolve(context, cachename, &cc);
3355 if (code) goto cleanup;
3357 code = krb5_cc_get_principal(context, cc, &princ);
3359 code = krb5_cc_default(context, &ncc);
3361 code = krb5_cc_initialize(context, ncc, princ);
3364 code = krb5_cc_copy_creds(context,cc,ncc);
3367 krb5_cc_close(context, ncc);
3371 retval=0; /* success */
3375 krb5_cc_close(context, cc);
3379 DeleteFile(filename);
3382 krb5_free_principal(context, princ);
3387 krb5_free_context(context);
3392 /* We are including this
3394 /* Ticket lifetime. This defines the table used to lookup lifetime for the
3395 fixed part of rande of the one byte lifetime field. Values less than 0x80
3396 are intrpreted as the number of 5 minute intervals. Values from 0x80 to
3397 0xBF should be looked up in this table. The value of 0x80 is the same using
3398 both methods: 10 and two-thirds hours . The lifetime of 0xBF is 30 days.
3399 The intervening values of have a fixed ratio of roughly 1.06914. The value
3400 oxFF is defined to mean a ticket has no expiration time. This should be
3401 used advisedly since individual servers may impose defacto upperbounds on
3402 ticket lifetimes. */
3404 #define TKTLIFENUMFIXED 64
3405 #define TKTLIFEMINFIXED 0x80
3406 #define TKTLIFEMAXFIXED 0xBF
3407 #define TKTLIFENOEXPIRE 0xFF
3408 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
3410 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3411 38400, /* 10.67 hours, 0.44 days */
3412 41055, /* 11.40 hours, 0.48 days */
3413 43894, /* 12.19 hours, 0.51 days */
3414 46929, /* 13.04 hours, 0.54 days */
3415 50174, /* 13.94 hours, 0.58 days */
3416 53643, /* 14.90 hours, 0.62 days */
3417 57352, /* 15.93 hours, 0.66 days */
3418 61318, /* 17.03 hours, 0.71 days */
3419 65558, /* 18.21 hours, 0.76 days */
3420 70091, /* 19.47 hours, 0.81 days */
3421 74937, /* 20.82 hours, 0.87 days */
3422 80119, /* 22.26 hours, 0.93 days */
3423 85658, /* 23.79 hours, 0.99 days */
3424 91581, /* 25.44 hours, 1.06 days */
3425 97914, /* 27.20 hours, 1.13 days */
3426 104684, /* 29.08 hours, 1.21 days */
3427 111922, /* 31.09 hours, 1.30 days */
3428 119661, /* 33.24 hours, 1.38 days */
3429 127935, /* 35.54 hours, 1.48 days */
3430 136781, /* 37.99 hours, 1.58 days */
3431 146239, /* 40.62 hours, 1.69 days */
3432 156350, /* 43.43 hours, 1.81 days */
3433 167161, /* 46.43 hours, 1.93 days */
3434 178720, /* 49.64 hours, 2.07 days */
3435 191077, /* 53.08 hours, 2.21 days */
3436 204289, /* 56.75 hours, 2.36 days */
3437 218415, /* 60.67 hours, 2.53 days */
3438 233517, /* 64.87 hours, 2.70 days */
3439 249664, /* 69.35 hours, 2.89 days */
3440 266926, /* 74.15 hours, 3.09 days */
3441 285383, /* 79.27 hours, 3.30 days */
3442 305116, /* 84.75 hours, 3.53 days */
3443 326213, /* 90.61 hours, 3.78 days */
3444 348769, /* 96.88 hours, 4.04 days */
3445 372885, /* 103.58 hours, 4.32 days */
3446 398668, /* 110.74 hours, 4.61 days */
3447 426234, /* 118.40 hours, 4.93 days */
3448 455705, /* 126.58 hours, 5.27 days */
3449 487215, /* 135.34 hours, 5.64 days */
3450 520904, /* 144.70 hours, 6.03 days */
3451 556921, /* 154.70 hours, 6.45 days */
3452 595430, /* 165.40 hours, 6.89 days */
3453 636601, /* 176.83 hours, 7.37 days */
3454 680618, /* 189.06 hours, 7.88 days */
3455 727680, /* 202.13 hours, 8.42 days */
3456 777995, /* 216.11 hours, 9.00 days */
3457 831789, /* 231.05 hours, 9.63 days */
3458 889303, /* 247.03 hours, 10.29 days */
3459 950794, /* 264.11 hours, 11.00 days */
3460 1016537, /* 282.37 hours, 11.77 days */
3461 1086825, /* 301.90 hours, 12.58 days */
3462 1161973, /* 322.77 hours, 13.45 days */
3463 1242318, /* 345.09 hours, 14.38 days */
3464 1328218, /* 368.95 hours, 15.37 days */
3465 1420057, /* 394.46 hours, 16.44 days */
3466 1518247, /* 421.74 hours, 17.57 days */
3467 1623226, /* 450.90 hours, 18.79 days */
3468 1735464, /* 482.07 hours, 20.09 days */
3469 1855462, /* 515.41 hours, 21.48 days */
3470 1983758, /* 551.04 hours, 22.96 days */
3471 2120925, /* 589.15 hours, 24.55 days */
3472 2267576, /* 629.88 hours, 26.25 days */
3473 2424367, /* 673.44 hours, 28.06 days */
3475 }; /* 720.00 hours, 30.00 days */
3477 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3478 * returns the corresponding end time. There are four simple cases to be
3479 * handled. The first is a life of 0xff, meaning no expiration, and results in
3480 * an end time of 0xffffffff. The second is when life is less than the values
3481 * covered by the table. In this case, the end time is the start time plus the
3482 * number of 5 minute intervals specified by life. The third case returns
3483 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
3484 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3485 * table to extract the lifetime in seconds, which is added to start to produce
3489 life_to_time(afs_uint32 start, unsigned char life)
3493 if (life == TKTLIFENOEXPIRE)
3495 if (life < TKTLIFEMINFIXED)
3496 return start + life * 5 * 60;
3497 if (life > TKTLIFEMAXFIXED)
3498 return start + MAXTKTLIFETIME;
3499 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3500 return start + realLife;
3503 /* time_to_life - takes start and end times for the ticket and returns a
3504 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3505 * lifetimes above 127*5minutes. First, the special case of (end ==
3506 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
3507 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
3508 * less than the first table entry are handled by rounding the requested
3509 * lifetime *up* to the next 5 minute interval. The final step is to search
3510 * the table for the smallest entry *greater than or equal* to the requested
3511 * entry. The actual code is prepared to handle the case where the table is
3512 * unordered but that it an unnecessary frill. */
3514 static unsigned char
3515 time_to_life(afs_uint32 start, afs_uint32 end)
3517 int lifetime = end - start;
3521 if (end == NEVERDATE)
3522 return TKTLIFENOEXPIRE;
3523 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
3525 if (lifetime < tkt_lifetimes[0])
3526 return (lifetime + 5 * 60 - 1) / (5 * 60);
3528 best = MAXKTCTICKETLIFETIME;
3529 for (i = 0; i < TKTLIFENUMFIXED; i++)
3530 if (tkt_lifetimes[i] >= lifetime) {
3531 int diff = tkt_lifetimes[i] - lifetime;
3539 return best_i + TKTLIFEMINFIXED;
3542 DWORD KFW_get_default_mslsa_import(krb5_context context)
3544 static const char * lsh_settings_key = "";
3545 static const char * lsh_mslsa_value = "";
3551 rc = RegOpenKeyEx(HKEY_CURRENT_USER, lsh_settings_key, 0, KEY_QUERY_VALUE, &hKey);
3555 dwCount = sizeof(DWORD);
3556 rc = RegQueryValueEx(hKey, lsh_mslsa_value, 0, 0, (LPBYTE) &import, &dwCount);
3562 rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lsh_settings_key, 0, KEY_QUERY_VALUE, &hKey);
3566 dwCount = sizeof(DWORD);
3567 rc = RegQueryValueEx(hKey, lsh_mslsa_value, 0, 0, (LPBYTE) &import, &dwCount);
3573 DWORD KFW_get_default_lifetime(krb5_context context, const char * realm)
3575 static const char * lifetime_val_name = "ticket_lifetime";
3578 krb5_appdefault_time(context, "aklog", realm, lifetime_val_name, 0, &t);
3581 t = krb5_config_get_time_default(context, NULL, 0,
3582 "realms", realm, lifetime_val_name, NULL);
3585 t = krb5_config_get_time_default(context, NULL, 0,
3586 "libdefaults", lifetime_val_name, NULL);