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 char * epname = NULL;
683 krb5_error_code code;
685 char temppath[MAX_PATH]="";
689 code = krb5_unparse_name(context, principal, &pname);
690 if (code) goto cleanup;
692 escape_unsafe_principal_characters(pname, &epname);
694 len = strlen(epname);
696 *cc_name = (char *) malloc(len);
698 GetTempPathA(MAX_PATH, temppath);
699 StringCbPrintfA(*cc_name, len, "FILE:%skrb5cc_%s", temppath, epname);
703 krb5_free_unparsed_name(context, pname);
712 is_default_ccache_for_principal(krb5_context context, krb5_principal principal,
715 const char * cc_name;
716 char * def_cc_name = NULL;
718 const char *bs_def_cc;
721 cc_name = krb5_cc_get_name(context, cc);
723 get_default_ccache_name_for_principal(context, principal, &def_cc_name);
725 is_default = (cc_name != NULL && def_cc_name != NULL &&
727 (bs_cc = strrchr(cc_name, '\\')) != NULL &&
729 (bs_def_cc = strrchr(def_cc_name, '\\')) != NULL &&
731 !strcmp(bs_cc, bs_def_cc));
739 /** Given a principal return an existing ccache or create one and return */
741 KFW_get_ccache(krb5_context alt_context, krb5_principal principal, krb5_ccache * cc)
743 krb5_context context = NULL;
745 char * ccname = NULL;
746 krb5_error_code code;
749 context = alt_context;
751 code = krb5_init_context(&context);
752 if (code) goto cleanup;
756 code = krb5_unparse_name(context, principal, &pname);
757 if (code) goto cleanup;
759 if ( !KFW_AFS_find_ccache_for_principal(context,pname,&ccname,TRUE) &&
760 !KFW_AFS_find_ccache_for_principal(context,pname,&ccname,FALSE)) {
762 get_default_ccache_name_for_principal(context, principal, &ccname);
764 code = krb5_cc_resolve(context, ccname, cc);
766 code = krb5_cc_default(context, cc);
767 if (code) goto cleanup;
774 krb5_free_unparsed_name(context,pname);
775 if (context && (context != alt_context))
776 krb5_free_context(context);
782 // Import Microsoft Credentials into a new MIT ccache
784 KFW_import_windows_lsa(void)
786 krb5_context context = NULL;
787 krb5_ccache cc = NULL;
788 krb5_principal princ = NULL;
790 const char * princ_realm;
791 krb5_error_code code;
792 char cell[128]="", realm[128]="", *def_realm = 0;
793 DWORD dwMsLsaImport = 1;
795 code = krb5_init_context(&context);
796 if (code) goto cleanup;
798 code = krb5_cc_resolve(context, LSA_CCNAME, &cc);
799 if (code) goto cleanup;
801 KFW_AFS_update_princ_ccache_data(context, cc, TRUE);
803 code = krb5_cc_get_principal(context, cc, &princ);
804 if ( code ) goto cleanup;
806 dwMsLsaImport = KFW_get_default_mslsa_import(context);
807 switch ( dwMsLsaImport ) {
808 case 0: /* do not import */
810 case 1: /* always import */
812 case 2: { /* matching realm */
813 const char *ms_realm;
815 ms_realm = krb5_principal_get_realm(context, princ);
817 if (code = krb5_get_default_realm(context, &def_realm))
820 if (strcmp(def_realm, ms_realm))
828 code = krb5_unparse_name(context,princ,&pname);
829 if ( code ) goto cleanup;
831 princ_realm = krb5_principal_get_realm(context, princ);
832 StringCchCopyA(realm, sizeof(realm), princ_realm);
833 StringCchCopyA(cell, sizeof(cell), princ_realm);
836 code = KFW_AFS_klog(context, cc, "afs", cell, realm,
837 KFW_get_default_lifetime(context, realm), NULL);
839 DebugPrintf("KFW_AFS_klog() returns: %d\n", code);
841 if ( code ) goto cleanup;
843 KFW_AFS_update_cell_princ_map(context, cell, pname, TRUE);
847 krb5_free_unparsed_name(context,pname);
849 krb5_free_principal(context,princ);
851 krb5_free_default_realm(context, def_realm);
853 krb5_cc_close(context,cc);
855 krb5_free_context(context);
857 #endif /* USE_MS2MIT */
860 get_canonical_ccache(krb5_context context, krb5_ccache * pcc)
862 krb5_error_code code;
863 krb5_ccache cc = *pcc;
864 krb5_principal principal = 0;
866 code = krb5_cc_get_principal(context, cc, &principal);
870 if ( !is_default_ccache_for_principal(context, principal, cc)
871 && strcmp(krb5_cc_get_type(context, cc), LSA_CCTYPE) != 0) {
873 char * def_cc_name = NULL;
874 krb5_ccache def_cc = 0;
875 krb5_principal def_cc_princ = 0;
878 get_default_ccache_name_for_principal(context, principal, &def_cc_name);
880 code = krb5_cc_resolve(context, def_cc_name, &def_cc);
883 code = krb5_cc_get_principal(context, def_cc, &def_cc_princ);
884 if (code || !krb5_principal_compare(context, def_cc_princ, principal)) {
885 /* def_cc either doesn't exist or is home to an
888 DebugPrintf("Copying ccache [%s:%s]->[%s:%s]",
889 krb5_cc_get_type(context, cc), krb5_cc_get_name(context, cc),
890 krb5_cc_get_type(context, def_cc),
891 krb5_cc_get_name(context, def_cc));
893 code = krb5_cc_initialize(context, def_cc, principal);
896 code = krb5_cc_copy_creds(context, cc, def_cc);
898 KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
902 code = krb5_cc_close(context, cc);
910 krb5_cc_close(context, def_cc);
913 krb5_free_principal(context, def_cc_princ);
920 krb5_free_principal(context, principal);
922 if (code == 0 && cc != 0) {
931 static krb5_error_code
932 check_and_get_tokens_for_ccache(krb5_context context, krb5_ccache cc)
934 krb5_error_code code = 0;
935 krb5_error_code cc_code = 0;
938 char * principal_name = NULL;
941 krb5_principal principal = 0;
942 code = krb5_cc_get_principal(context, cc, &principal);
945 code = krb5_unparse_name(context, principal, &principal_name);
948 krb5_free_principal(context, principal);
953 krb5_free_unparsed_name(context, principal_name);
957 cc_code = krb5_cc_start_seq_get(context, cc, &cur);
959 while (!(cc_code = krb5_cc_next_cred(context, cc, &cur, &creds))) {
961 const char * sname = krb5_principal_get_comp_string(context, creds.server, 0);
962 const char * cell = krb5_principal_get_comp_string(context, creds.server, 1);
963 const char * realm = krb5_principal_get_realm(context, creds.server);
965 if ( sname && cell && !strcmp("afs",sname) ) {
967 struct ktc_principal aserver;
968 struct ktc_principal aclient;
969 struct ktc_token atoken;
972 DebugPrintf("Found AFS ticket: %s%s%s@%s\n",
973 sname, (cell ? "/":""), (cell? cell : ""), realm);
975 memset(&aserver, '\0', sizeof(aserver));
976 StringCbCopy(aserver.name, sizeof(aserver.name), sname);
977 StringCbCopy(aserver.cell, sizeof(aserver.cell), cell);
979 code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
981 // Found a token in AFS Client Server which matches
983 char pname[128], *p, *q;
985 for ( p=pname, q=aclient.name; *q; p++, q++)
988 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
993 DebugPrintf("Found AFS token: %s\n", pname);
995 if (strcmp(pname, principal_name) != 0)
998 KFW_AFS_update_cell_princ_map(context, cell, principal_name, active);
1001 // Attempt to import it
1003 KFW_AFS_update_cell_princ_map(context, cell, principal_name, active);
1005 DebugPrintf("Calling KFW_AFS_klog() to obtain token\n");
1007 code = KFW_AFS_klog(context, cc, "afs", cell, realm,
1008 KFW_get_default_lifetime(context, realm), NULL);
1010 DebugPrintf("KFW_AFS_klog() returns: %d\n", code);
1015 DebugPrintf("Found ticket: %s%s%s@%s\n", sname,
1016 (cell? "/":""), (cell? cell:""), realm);
1019 krb5_free_cred_contents(context, &creds);
1022 if (cc_code == KRB5_CC_END) {
1023 cc_code = krb5_cc_end_seq_get(context, cc, &cur);
1029 // If there are existing MIT credentials, copy them to a new
1030 // ccache named after the principal
1032 // Enumerate all existing MIT ccaches and construct entries
1033 // in the principal_ccache table
1035 // Enumerate all existing AFS Tokens and construct entries
1036 // in the cell_principal table
1038 KFW_import_ccache_data(void)
1040 krb5_context context = NULL;
1042 krb5_error_code code;
1043 krb5_cccol_cursor cccol_cur;
1046 if ( IsDebuggerPresent() )
1047 OutputDebugString("KFW_import_ccache_data()\n");
1049 code = krb5_init_context(&context);
1050 if (code) goto cleanup;
1052 code = krb5_cccol_cursor_new(context, &cccol_cur);
1053 if (code) goto cleanup;
1055 while ((code = krb5_cccol_cursor_next(context, cccol_cur, &cc)) == 0 && cc != NULL) {
1057 if (!get_canonical_ccache(context, &cc)) {
1059 krb5_cc_close(context, cc);
1063 /* Turn off OPENCLOSE mode */
1064 code = krb5_cc_set_flags(context, cc, 0);
1065 if ( code ) goto cleanup;
1067 KFW_AFS_update_princ_ccache_data(context, cc,
1068 !strcmp(krb5_cc_get_type(context, cc),
1071 check_and_get_tokens_for_ccache(context, cc);
1073 flags = KRB5_TC_OPENCLOSE; //turn on OPENCLOSE
1074 code = krb5_cc_set_flags(context, cc, flags);
1077 krb5_cc_close(context,cc);
1082 krb5_cccol_cursor_free(context, &cccol_cur);
1086 krb5_free_context(context);
1090 KFW_enable_DES(krb5_context alt_context)
1092 krb5_context context;
1093 krb5_error_code code;
1095 if ( alt_context ) {
1096 context = alt_context;
1098 code = krb5_init_context(&context);
1099 if (code) goto cleanup;
1102 if (krb5_enctype_valid(context, ETYPE_DES_CBC_CRC))
1103 krb5_enctype_enable(context, ETYPE_DES_CBC_CRC);
1106 if (context && (context != alt_context))
1107 krb5_free_context(context);
1112 KFW_AFS_get_cred( char * username,
1119 static char reason[1024]="";
1120 krb5_context context = NULL;
1121 krb5_ccache cc = NULL;
1122 char * realm = NULL, * userrealm = NULL;
1123 krb5_principal principal = NULL;
1124 char * pname = NULL;
1125 krb5_error_code code;
1126 char local_cell[CELL_MAXNAMELEN+1];
1127 char **cells = NULL;
1129 struct afsconf_cell cellconfig;
1132 DebugPrintf("KFW_AFS_get_cred for token %s in cell %s\n", username, cell);
1134 memset(&cellconfig, 0, sizeof(cellconfig));
1136 code = krb5_init_context(&context);
1137 if ( code ) goto cleanup;
1139 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1140 if ( code ) goto cleanup;
1142 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1144 userrealm = strchr(username,'@');
1146 pname = strdup(username);
1147 if (!KFW_accept_dotted_usernames()) {
1148 userrealm = strchr(pname, '@');
1151 /* handle kerberos iv notation */
1152 while ( dot = strchr(pname,'.') ) {
1159 size_t len = strlen(username) + strlen(realm) + 2;
1160 pname = malloc(len);
1161 if (pname == NULL) {
1162 code = KRB5KRB_ERR_GENERIC;
1165 StringCbCopy(pname, len, username);
1167 if (!KFW_accept_dotted_usernames()) {
1168 /* handle kerberos iv notation */
1169 while ( dot = strchr(pname,'.') ) {
1173 StringCbCat( pname, len, "@");
1174 StringCbCat( pname, len, realm);
1176 if ( IsDebuggerPresent() ) {
1177 OutputDebugString("Realm of Cell: ");
1178 OutputDebugString(realm);
1179 OutputDebugString("\n");
1180 OutputDebugString("Realm of User: ");
1181 OutputDebugString(userrealm?userrealm:"<NULL>");
1182 OutputDebugString("\n");
1185 code = krb5_parse_name(context, pname, &principal);
1186 if ( code ) goto cleanup;
1188 code = KFW_get_ccache(context, principal, &cc);
1189 if ( code ) goto cleanup;
1191 if ( lifetime == 0 )
1192 lifetime = KFW_get_default_lifetime(context, realm);
1194 if ( password && password[0] ) {
1195 code = KFW_kinit( context, cc, HWND_DESKTOP,
1200 0, /* forwardable */
1201 0, /* not proxiable */
1203 1, /* noaddresses */
1204 0 /* no public ip */
1206 pLeash_get_default_forwardable(),
1207 pLeash_get_default_proxiable(),
1208 pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1209 pLeash_get_default_noaddresses(),
1210 pLeash_get_default_publicip()
1211 #endif /* USE_LEASH */
1214 if ( IsDebuggerPresent() ) {
1216 StringCbPrintf(message, sizeof(message), "KFW_kinit() returns: %d\n", code);
1217 OutputDebugString(message);
1219 if ( code ) goto cleanup;
1221 KFW_AFS_update_princ_ccache_data(context, cc, FALSE);
1224 code = KFW_AFS_klog(context, cc, "afs", cell, realm, lifetime, smbname);
1225 if ( IsDebuggerPresent() ) {
1227 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1228 OutputDebugString(message);
1230 if ( code ) goto cleanup;
1232 KFW_AFS_update_cell_princ_map(context, cell, pname, TRUE);
1234 // Attempt to obtain new tokens for other cells supported by the same
1236 cell_count = KFW_AFS_find_cells_for_princ(context, pname, &cells, TRUE);
1237 if ( cell_count > 1 ) {
1238 while ( cell_count-- ) {
1239 if ( strcmp(cells[cell_count],cell) ) {
1240 if ( IsDebuggerPresent() ) {
1242 StringCbPrintf(message, sizeof(message),
1243 "found another cell for the same principal: %s\n", cell);
1244 OutputDebugString(message);
1247 if (cellconfig.linkedCell) {
1248 free(cellconfig.linkedCell);
1249 cellconfig.linkedCell = NULL;
1251 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1252 if ( code ) continue;
1254 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1255 if ( IsDebuggerPresent() ) {
1256 OutputDebugString("Realm: ");
1257 OutputDebugString(realm);
1258 OutputDebugString("\n");
1261 code = KFW_AFS_klog(context, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1262 if ( IsDebuggerPresent() ) {
1264 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1265 OutputDebugString(message);
1268 free(cells[cell_count]);
1271 } else if ( cell_count == 1 ) {
1280 krb5_cc_close(context, cc);
1281 if ( cellconfig.linkedCell )
1282 free(cellconfig.linkedCell);
1284 if ( code && reasonP ) {
1285 const char *msg = krb5_get_error_message(context, code);
1286 StringCbCopyN( reason, sizeof(reason),
1287 msg, sizeof(reason) - 1);
1289 krb5_free_error_message(context, msg);
1295 KFW_AFS_destroy_tickets_for_cell(char * cell)
1297 krb5_context context = NULL;
1298 krb5_error_code code;
1300 char ** principals = NULL;
1302 DebugPrintf("KFW_AFS_destroy_tickets_for_cell: %s\n", cell);
1304 code = krb5_init_context(&context);
1305 if (code) context = 0;
1307 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, FALSE);
1309 krb5_principal princ = 0;
1313 int cell_count = KFW_AFS_find_cells_for_princ(context, principals[count], NULL, TRUE);
1314 if ( cell_count > 1 ) {
1315 // TODO - What we really should do here is verify whether or not any of the
1316 // other cells which use this principal to obtain its credentials actually
1317 // have valid tokens or not. If they are currently using these credentials
1318 // we will skip them. For the time being we assume that if there is an active
1319 // map in the table that they are actively being used.
1323 code = krb5_parse_name(context, principals[count], &princ);
1324 if (code) goto loop_cleanup;
1326 code = KFW_get_ccache(context, princ, &cc);
1327 if (code) goto loop_cleanup;
1329 code = krb5_cc_destroy(context, cc);
1334 krb5_cc_close(context, cc);
1338 krb5_free_principal(context, princ);
1342 KFW_AFS_update_cell_princ_map(context, cell, principals[count], FALSE);
1343 free(principals[count]);
1348 krb5_free_context(context);
1353 KFW_AFS_destroy_tickets_for_principal(char * user)
1355 krb5_context context = NULL;
1356 krb5_error_code code;
1358 char ** cells = NULL;
1359 krb5_principal princ = NULL;
1360 krb5_ccache cc = NULL;
1362 DebugPrintf("KFW_AFS_destroy_tickets_for_user: %s\n", user);
1364 code = krb5_init_context(&context);
1367 code = krb5_parse_name(context, user, &princ);
1368 if (code) goto loop_cleanup;
1370 code = KFW_get_ccache(context, princ, &cc);
1371 if (code) goto loop_cleanup;
1373 code = krb5_cc_destroy(context, cc);
1378 krb5_cc_close(context, cc);
1382 krb5_free_principal(context, princ);
1386 count = KFW_AFS_find_cells_for_princ(context, user, &cells, TRUE);
1389 KFW_AFS_update_cell_princ_map(context, cells[count], user, FALSE);
1396 krb5_free_context(context);
1402 KFW_AFS_renew_expiring_tokens(void)
1404 krb5_error_code code = 0;
1405 krb5_context context = NULL;
1406 krb5_ccache cc = NULL;
1408 struct principal_ccache_data * pcc_next = princ_cc_data;
1411 const char * realm = NULL;
1412 char local_cell[CELL_MAXNAMELEN+1]="";
1413 struct afsconf_cell cellconfig;
1415 if ( pcc_next == NULL ) // nothing to do
1418 if ( IsDebuggerPresent() ) {
1419 OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1422 memset(&cellconfig, 0, sizeof(cellconfig));
1424 code = krb5_init_context(&context);
1425 if (code) goto cleanup;
1427 code = krb5_timeofday(context, &now);
1428 if (code) goto cleanup;
1430 for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1431 if ( pcc_next->expired )
1434 if ( now >= (pcc_next->expiration_time) ) {
1435 if ( !pcc_next->from_lsa ) {
1436 pcc_next->expired = 1;
1441 if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1442 code = krb5_cc_resolve(context, pcc_next->ccache_name, &cc);
1445 code = KFW_renew(context,cc);
1447 if ( code && pcc_next->from_lsa)
1449 #endif /* USE_MS2MIT */
1452 KFW_AFS_update_princ_ccache_data(context, cc, pcc_next->from_lsa);
1453 if (code) goto loop_cleanup;
1455 // Attempt to obtain new tokens for other cells supported by the same
1457 cell_count = KFW_AFS_find_cells_for_princ(context, pcc_next->principal, &cells, TRUE);
1458 if ( cell_count > 0 ) {
1459 while ( cell_count-- ) {
1460 if ( IsDebuggerPresent() ) {
1461 OutputDebugString("Cell: ");
1462 OutputDebugString(cells[cell_count]);
1463 OutputDebugString("\n");
1465 if (cellconfig.linkedCell) {
1466 free(cellconfig.linkedCell);
1467 cellconfig.linkedCell = NULL;
1469 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1470 if ( code ) continue;
1471 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1472 if ( IsDebuggerPresent() ) {
1473 OutputDebugString("Realm: ");
1474 OutputDebugString(realm);
1475 OutputDebugString("\n");
1477 code = KFW_AFS_klog(context, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1478 if ( IsDebuggerPresent() ) {
1480 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1481 OutputDebugString(message);
1483 free(cells[cell_count]);
1491 krb5_cc_close(context,cc);
1498 krb5_cc_close(context,cc);
1500 krb5_free_context(context);
1501 if (cellconfig.linkedCell)
1502 free(cellconfig.linkedCell);
1509 KFW_AFS_renew_token_for_cell(char * cell)
1511 krb5_error_code code = 0;
1512 krb5_context context = NULL;
1514 char ** principals = NULL;
1516 if ( IsDebuggerPresent() ) {
1517 OutputDebugString("KFW_AFS_renew_token_for_cell:");
1518 OutputDebugString(cell);
1519 OutputDebugString("\n");
1522 code = krb5_init_context(&context);
1523 if (code) goto cleanup;
1525 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, TRUE);
1527 // We know we must have a credential somewhere since we are
1528 // trying to renew a token
1530 KFW_import_ccache_data();
1531 count = KFW_AFS_find_principals_for_cell(context, cell, &principals, TRUE);
1534 krb5_principal princ = 0;
1535 krb5_principal service = 0;
1537 krb5_creds mcreds, creds;
1538 #endif /* COMMENT */
1540 const char * realm = NULL;
1541 struct afsconf_cell cellconfig;
1542 char local_cell[CELL_MAXNAMELEN+1];
1544 memset(&cellconfig, 0, sizeof(cellconfig));
1547 code = krb5_parse_name(context, principals[count], &princ);
1548 if (code) goto loop_cleanup;
1550 code = KFW_get_ccache(context, princ, &cc);
1551 if (code) goto loop_cleanup;
1553 if (cellconfig.linkedCell) {
1554 free(cellconfig.linkedCell);
1555 cellconfig.linkedCell = NULL;
1557 code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1558 if ( code ) goto loop_cleanup;
1560 realm = afs_realm_of_cell(context, &cellconfig); // do not free
1561 if ( IsDebuggerPresent() ) {
1562 OutputDebugString("Realm: ");
1563 OutputDebugString(realm);
1564 OutputDebugString("\n");
1568 /* krb5_cc_remove_cred() is not implemented
1571 code = krb5_build_principal(context, &service, strlen(realm),
1572 realm, "afs", cell, NULL);
1574 memset(&mcreds, 0, sizeof(krb5_creds));
1575 mcreds.client = princ;
1576 mcreds.server = service;
1578 code = krb5_cc_retrieve_cred(context, cc, 0, &mcreds, &creds);
1580 if ( IsDebuggerPresent() ) {
1581 char * cname, *sname;
1582 krb5_unparse_name(context, creds.client, &cname);
1583 krb5_unparse_name(context, creds.server, &sname);
1584 OutputDebugString("Removing credential for client \"");
1585 OutputDebugString(cname);
1586 OutputDebugString("\" and service \"");
1587 OutputDebugString(sname);
1588 OutputDebugString("\"\n");
1589 krb5_free_unparsed_name(context,cname);
1590 krb5_free_unparsed_name(context,sname);
1593 code = krb5_cc_remove_cred(context, cc, 0, &creds);
1594 krb5_free_principal(context, creds.client);
1595 krb5_free_principal(context, creds.server);
1598 #endif /* COMMENT */
1600 code = KFW_AFS_klog(context, cc, "afs", cell, (char *)realm, 0,NULL);
1601 if ( IsDebuggerPresent() ) {
1603 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1604 OutputDebugString(message);
1609 krb5_cc_close(context, cc);
1613 krb5_free_principal(context, princ);
1617 krb5_free_principal(context, service);
1620 if (cellconfig.linkedCell) {
1621 free(cellconfig.linkedCell);
1622 cellconfig.linkedCell = NULL;
1625 KFW_AFS_update_cell_princ_map(context, cell, principals[count], code ? FALSE : TRUE);
1626 free(principals[count]);
1630 code = -1; // we did not renew the tokens
1634 krb5_free_context(context);
1635 return (code ? FALSE : TRUE);
1640 KFW_AFS_renew_tokens_for_all_cells(void)
1642 struct cell_principal_map * next = cell_princ_map;
1644 DebugPrintf("KFW_AFS_renew_tokens_for_all()\n");
1649 for ( ; next ; next = next->next ) {
1651 KFW_AFS_renew_token_for_cell(next->cell);
1657 KFW_renew(krb5_context alt_context, krb5_ccache alt_cc)
1659 krb5_error_code code = 0;
1660 krb5_context context = NULL;
1661 krb5_ccache cc = NULL;
1662 krb5_principal me = NULL;
1663 krb5_principal server = NULL;
1664 krb5_creds my_creds;
1665 const char *realm = NULL;
1667 memset(&my_creds, 0, sizeof(krb5_creds));
1669 if ( alt_context ) {
1670 context = alt_context;
1672 code = krb5_init_context(&context);
1673 if (code) goto cleanup;
1679 code = krb5_cc_default(context, &cc);
1680 if (code) goto cleanup;
1683 code = krb5_cc_get_principal(context, cc, &me);
1684 if (code) goto cleanup;
1686 realm = krb5_principal_get_realm(context, me);
1688 code = krb5_make_principal(context, &server, realm,
1689 KRB5_TGS_NAME, realm, NULL);
1693 if ( IsDebuggerPresent() ) {
1694 char * cname, *sname;
1695 krb5_unparse_name(context, me, &cname);
1696 krb5_unparse_name(context, server, &sname);
1697 DebugPrintf("Renewing credential for client \"%s\" and service\"%s\"\n",
1699 krb5_free_unparsed_name(context,cname);
1700 krb5_free_unparsed_name(context,sname);
1703 my_creds.client = me;
1704 my_creds.server = server;
1706 code = krb5_get_renewed_creds(context, &my_creds, me, cc, NULL);
1708 DebugPrintf("krb5_get_renewed_creds() failed: %d\n", code);
1712 code = krb5_cc_initialize(context, cc, me);
1714 DebugPrintf("krb5_cc_initialize() failed: %d\n", code);
1718 code = krb5_cc_store_cred(context, cc, &my_creds);
1720 DebugPrintf("krb5_cc_store_cred() failed: %d\n", code);
1725 if (my_creds.client == me)
1726 my_creds.client = 0;
1727 if (my_creds.server == server)
1728 my_creds.server = 0;
1729 krb5_free_cred_contents(context, &my_creds);
1731 krb5_free_principal(context, me);
1733 krb5_free_principal(context, server);
1734 if (cc && (cc != alt_cc))
1735 krb5_cc_close(context, cc);
1736 if (context && (context != alt_context))
1737 krb5_free_context(context);
1742 KFW_kinit( krb5_context alt_context,
1745 char *principal_name,
1747 krb5_deltat lifetime,
1750 krb5_deltat renew_life,
1754 krb5_error_code code = 0;
1755 krb5_context context = NULL;
1756 krb5_ccache cc = NULL;
1757 krb5_principal me = NULL;
1759 krb5_creds my_creds;
1760 krb5_get_init_creds_opt *options = NULL;
1761 krb5_addresses addrs = {0, NULL};
1762 int i = 0, addr_count = 0;
1764 memset(&my_creds, 0, sizeof(my_creds));
1767 context = alt_context;
1769 code = krb5_init_context(&context);
1770 if (code) goto cleanup;
1776 code = krb5_cc_default(context, &cc);
1777 if (code) goto cleanup;
1780 code = krb5_get_init_creds_opt_alloc(context, &options);
1781 if (code) goto cleanup;
1783 code = krb5_parse_name(context, principal_name, &me);
1784 if (code) goto cleanup;
1786 code = krb5_unparse_name(context, me, &name);
1787 if (code) goto cleanup;
1790 lifetime = KFW_get_default_lifetime(context,
1791 krb5_principal_get_realm(context, me));
1799 krb5_get_init_creds_opt_set_tkt_life(options, lifetime);
1800 krb5_get_init_creds_opt_set_forwardable(options, forwardable ? 1 : 0);
1801 krb5_get_init_creds_opt_set_proxiable(options, proxiable ? 1 : 0);
1802 krb5_get_init_creds_opt_set_renew_life(options, renew_life);
1804 krb5_get_init_creds_opt_set_addressless(context, options, TRUE);
1807 // we are going to add the public IP address specified by the user
1808 // to the list provided by the operating system
1809 struct sockaddr_in in_addr;
1811 krb5_addresses addr_l;
1813 krb5_get_all_client_addrs(context, &addrs);
1815 in_addr.sin_family = AF_INET;
1816 in_addr.sin_port = 0;
1817 in_addr.sin_addr.S_un.S_addr = htonl(publicIP);
1819 code = krb5_sockaddr2address(context, (struct sockaddr *)&in_addr,
1826 code = krb5_append_addresses(context, &addrs, &addr_l);
1828 krb5_free_address(context, &addr);
1831 krb5_get_init_creds_opt_set_address_list(options, &addrs);
1835 code = krb5_get_init_creds_password(context,
1838 password, // password
1839 KRB5_prompter, // prompter
1840 hParent, // prompter data
1847 code = krb5_cc_initialize(context, cc, me);
1851 code = krb5_cc_store_cred(context, cc, &my_creds);
1856 if ( addrs.len > 0 )
1857 krb5_free_addresses(context, &addrs);
1859 if (my_creds.client == me)
1860 my_creds.client = 0;
1862 krb5_free_cred_contents(context, &my_creds);
1864 krb5_free_unparsed_name(context, name);
1866 krb5_free_principal(context, me);
1868 krb5_get_init_creds_opt_free(context, options);
1869 if (cc && (cc != alt_cc))
1870 krb5_cc_close(context, cc);
1871 if (context && (context != alt_context))
1872 krb5_free_context(context);
1878 KFW_kdestroy(krb5_context alt_context, krb5_ccache alt_cc)
1880 krb5_context context = NULL;
1881 krb5_ccache cc = NULL;
1882 krb5_error_code code;
1885 context = alt_context;
1887 code = krb5_init_context(&context);
1888 if (code) goto cleanup;
1894 code = krb5_cc_default(context, &cc);
1895 if (code) goto cleanup;
1898 code = krb5_cc_destroy(context, cc);
1899 if ( !code ) cc = 0;
1902 if (cc && (cc != alt_cc))
1903 krb5_cc_close(context, cc);
1904 if (context && (context != alt_context))
1905 krb5_free_context(context);
1913 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1915 NTSTATUS Status = 0;
1917 TOKEN_STATISTICS Stats;
1923 *ppSessionData = NULL;
1925 Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1929 Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1930 CloseHandle( TokenHandle );
1934 Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1935 if ( FAILED(Status) || !ppSessionData )
1942 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
1943 // cache. It validates whether or not it is reasonable to assume that if we
1944 // attempted to retrieve valid tickets we could do so. Microsoft does not
1945 // automatically renew expired tickets. Therefore, the cache could contain
1946 // expired or invalid tickets. Microsoft also caches the user's password
1947 // and will use it to retrieve new TGTs if the cache is empty and tickets
1951 MSLSA_IsKerberosLogon(VOID)
1953 PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
1954 BOOL Success = FALSE;
1956 if ( GetSecurityLogonSessionData(&pSessionData) ) {
1957 if ( pSessionData->AuthenticationPackage.Buffer ) {
1963 usBuffer = (pSessionData->AuthenticationPackage).Buffer;
1964 usLength = (pSessionData->AuthenticationPackage).Length;
1967 StringCbCopyNW( buffer, sizeof(buffer)/sizeof(WCHAR),
1968 usBuffer, usLength);
1969 if ( !lstrcmpW(L"Kerberos",buffer) )
1973 LsaFreeReturnBuffer(pSessionData);
1977 #endif /* USE_MS2MIT */
1979 static BOOL CALLBACK
1980 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
1984 switch ( message ) {
1986 if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
1988 SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
1991 for ( i=0; i < mid_cnt ; i++ ) {
1992 if (mid_tb[i].echo == 0)
1993 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
1994 else if (mid_tb[i].echo == 2)
1995 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
2000 switch ( LOWORD(wParam) ) {
2002 for ( i=0; i < mid_cnt ; i++ ) {
2003 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
2004 *mid_tb[i].buf = '\0';
2008 EndDialog(hDialog, LOWORD(wParam));
2016 lpwAlign( LPWORD lpIn )
2020 ul = (ULONG_PTR) lpIn;
2024 return (LPWORD) ul;;
2028 * dialog widths are measured in 1/4 character widths
2029 * dialog height are measured in 1/8 character heights
2033 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2034 char * ptext[], int numlines, int width,
2035 int tb_cnt, struct textField * tb)
2039 LPDLGITEMTEMPLATE lpdit;
2045 hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2052 lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2054 // Define a dialog box.
2056 lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2057 | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2058 | DS_SETFOREGROUND | DS_3DLOOK
2059 | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2060 lpdt->cdit = numlines + (2 * tb_cnt) + 2; // number of controls
2063 lpdt->cx = 20 + width * 4;
2064 lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2066 lpw = (LPWORD) (lpdt + 1);
2067 *lpw++ = 0; // no menu
2068 *lpw++ = 0; // predefined dialog box class (by default)
2070 lpwsz = (LPWSTR) lpw;
2071 nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2073 *lpw++ = 8; // font size (points)
2074 lpwsz = (LPWSTR) lpw;
2075 nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2079 //-----------------------
2080 // Define an OK button.
2081 //-----------------------
2082 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2083 lpdit = (LPDLGITEMTEMPLATE) lpw;
2084 lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2085 lpdit->dwExtendedStyle = 0;
2086 lpdit->x = (lpdt->cx - 14)/4 - 20;
2087 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2090 lpdit->id = IDOK; // OK button identifier
2092 lpw = (LPWORD) (lpdit + 1);
2094 *lpw++ = 0x0080; // button class
2096 lpwsz = (LPWSTR) lpw;
2097 nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2099 *lpw++ = 0; // no creation data
2101 //-----------------------
2102 // Define an Cancel button.
2103 //-----------------------
2104 lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2105 lpdit = (LPDLGITEMTEMPLATE) lpw;
2106 lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2107 lpdit->dwExtendedStyle = 0;
2108 lpdit->x = (lpdt->cx - 14)*3/4 - 20;
2109 lpdit->y = 10 + (numlines + tb_cnt + 2) * 14;
2112 lpdit->id = IDCANCEL; // CANCEL button identifier
2114 lpw = (LPWORD) (lpdit + 1);
2116 *lpw++ = 0x0080; // button class
2118 lpwsz = (LPWSTR) lpw;
2119 nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2121 *lpw++ = 0; // no creation data
2123 /* Add controls for preface data */
2124 for ( i=0; i<numlines; i++) {
2125 /*-----------------------
2126 * Define a static text control.
2127 *-----------------------*/
2128 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2129 lpdit = (LPDLGITEMTEMPLATE) lpw;
2130 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2131 lpdit->dwExtendedStyle = 0;
2133 lpdit->y = 10 + i * 14;
2134 lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2136 lpdit->id = ID_TEXT + i; // text identifier
2138 lpw = (LPWORD) (lpdit + 1);
2140 *lpw++ = 0x0082; // static class
2142 lpwsz = (LPWSTR) lpw;
2143 nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2144 -1, lpwsz, 2*width);
2146 *lpw++ = 0; // no creation data
2149 for ( i=0, pwid = 0; i<tb_cnt; i++) {
2150 int len = (int)strlen(tb[i].label);
2155 for ( i=0; i<tb_cnt; i++) {
2157 /*-----------------------
2158 * Define a static text control.
2159 *-----------------------*/
2160 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2161 lpdit = (LPDLGITEMTEMPLATE) lpw;
2162 lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2163 lpdit->dwExtendedStyle = 0;
2165 lpdit->y = 10 + (numlines + i + 1) * 14;
2166 lpdit->cx = pwid * 4;
2168 lpdit->id = ID_TEXT + numlines + i; // text identifier
2170 lpw = (LPWORD) (lpdit + 1);
2172 *lpw++ = 0x0082; // static class
2174 lpwsz = (LPWSTR) lpw;
2175 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2178 *lpw++ = 0; // no creation data
2180 /*-----------------------
2181 * Define an edit control.
2182 *-----------------------*/
2183 lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2184 lpdit = (LPDLGITEMTEMPLATE) lpw;
2185 lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2186 lpdit->dwExtendedStyle = 0;
2187 lpdit->x = 10 + (pwid + 1) * 4;
2188 lpdit->y = 10 + (numlines + i + 1) * 14;
2189 lpdit->cx = (width - (pwid + 1)) * 4;
2191 lpdit->id = ID_MID_TEXT + i; // identifier
2193 lpw = (LPWORD) (lpdit + 1);
2195 *lpw++ = 0x0081; // edit class
2197 lpwsz = (LPWSTR) lpw;
2198 nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2201 *lpw++ = 0; // no creation data
2205 ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2206 hwndOwner, (DLGPROC) MultiInputDialogProc);
2210 case 0: /* Timeout */
2218 StringCbPrintf(buf, sizeof(buf), "DialogBoxIndirect() failed: %d", GetLastError());
2219 MessageBox(hwndOwner,
2222 MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2229 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2231 HINSTANCE hInst = 0;
2232 size_t maxwidth = 0;
2235 char * plines[16], *p = preface ? preface : "";
2238 for ( i=0; i<16; i++ )
2241 while (*p && numlines < 16) {
2242 plines[numlines++] = p;
2243 for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2244 if ( *p == '\r' && *(p+1) == '\n' ) {
2247 } else if ( *p == '\n' ) {
2250 if ( strlen(plines[numlines-1]) > maxwidth )
2251 maxwidth = strlen(plines[numlines-1]);
2254 for ( i=0;i<n;i++ ) {
2255 len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2256 if ( maxwidth < len )
2260 return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2263 static krb5_error_code KRB5_CALLCONV
2264 KRB5_prompter( krb5_context context,
2269 krb5_prompt prompts[])
2271 krb5_error_code errcode = 0;
2273 struct textField * tb = NULL;
2274 int len = 0, blen=0, nlen=0;
2275 HWND hParent = (HWND)data;
2278 nlen = (int)strlen(name)+2;
2281 blen = (int)strlen(banner)+2;
2283 tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2286 memset(tb,0,sizeof(struct textField) * num_prompts);
2287 for ( i=0; i < num_prompts; i++ ) {
2288 tb[i].buf = prompts[i].reply->data;
2289 tb[i].len = prompts[i].reply->length;
2290 tb[i].label = prompts[i].prompt;
2292 tb[i].echo = (prompts[i].hidden ? 2 : 1);
2295 ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2297 for ( i=0; i < num_prompts; i++ )
2298 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2306 for (i = 0; i < num_prompts; i++) {
2307 memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2314 KFW_AFS_wait_for_service_start(void)
2319 CurrentState = SERVICE_START_PENDING;
2320 memset(HostName, '\0', sizeof(HostName));
2321 gethostname(HostName, sizeof(HostName));
2323 while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2325 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2327 if ( IsDebuggerPresent() ) {
2328 switch ( CurrentState ) {
2329 case SERVICE_STOPPED:
2330 OutputDebugString("SERVICE_STOPPED\n");
2332 case SERVICE_START_PENDING:
2333 OutputDebugString("SERVICE_START_PENDING\n");
2335 case SERVICE_STOP_PENDING:
2336 OutputDebugString("SERVICE_STOP_PENDING\n");
2338 case SERVICE_RUNNING:
2339 OutputDebugString("SERVICE_RUNNING\n");
2341 case SERVICE_CONTINUE_PENDING:
2342 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2344 case SERVICE_PAUSE_PENDING:
2345 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2347 case SERVICE_PAUSED:
2348 OutputDebugString("SERVICE_PAUSED\n");
2351 OutputDebugString("UNKNOWN Service State\n");
2354 if (CurrentState == SERVICE_STOPPED)
2356 if (CurrentState == SERVICE_RUNNING)
2372 memset(HostName, '\0', sizeof(HostName));
2373 gethostname(HostName, sizeof(HostName));
2374 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2376 if (CurrentState != SERVICE_RUNNING)
2379 rc = ktc_ForgetAllTokens();
2385 #define ALLOW_REGISTER 1
2387 ViceIDToUsername(char *username,
2388 char *realm_of_user,
2389 char *realm_of_cell,
2391 struct ktc_principal *aclient,
2392 struct ktc_principal *aserver,
2393 struct ktc_token *atoken)
2395 static char lastcell[CELL_MAXNAMELEN+1] = { 0 };
2396 static char confdir[512] = { 0 };
2397 #ifdef AFS_ID_TO_NAME
2398 char username_copy[BUFSIZ];
2399 #endif /* AFS_ID_TO_NAME */
2400 long viceId = ANONYMOUSID; /* AFS uid of user */
2402 #ifdef ALLOW_REGISTER
2404 #endif /* ALLOW_REGISTER */
2406 if (confdir[0] == '\0')
2407 cm_GetConfigDir(confdir, sizeof(confdir));
2409 StringCbCopyN( lastcell, sizeof(lastcell),
2410 aserver->cell, sizeof(lastcell) - 1);
2412 if (!pr_Initialize (0, confdir, aserver->cell)) {
2413 char sname[PR_MAXNAMELEN];
2414 StringCbCopyN( sname, sizeof(sname),
2415 username, sizeof(sname) - 1);
2416 status = pr_SNameToId (sname, &viceId);
2421 * This is a crock, but it is Transarc's crock, so
2422 * we have to play along in order to get the
2423 * functionality. The way the afs id is stored is
2424 * as a string in the username field of the token.
2425 * Contrary to what you may think by looking at
2426 * the code for tokens, this hack (AFS ID %d) will
2427 * not work if you change %d to something else.
2431 * This code is taken from cklog -- it lets people
2432 * automatically register with the ptserver in foreign cells
2435 #ifdef ALLOW_REGISTER
2437 if (viceId != ANONYMOUSID) {
2438 #else /* ALLOW_REGISTER */
2439 if ((status == 0) && (viceId != ANONYMOUSID))
2440 #endif /* ALLOW_REGISTER */
2442 #ifdef AFS_ID_TO_NAME
2443 StringCbCopyN( username_copy, sizeof(username_copy),
2444 username, sizeof(username_copy) - 1);
2445 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2446 #endif /* AFS_ID_TO_NAME */
2448 #ifdef ALLOW_REGISTER
2449 } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2451 StringCbCopyN( aclient->name, sizeof(aclient->name),
2452 username, sizeof(aclient->name) - 1);
2453 aclient->instance[0] = '\0';
2454 StringCbCopyN( aclient->cell, sizeof(aclient->cell),
2455 realm_of_user, sizeof(aclient->cell) - 1);
2456 if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2458 if (status = pr_Initialize(1L, confdir, aserver->cell))
2460 status = pr_CreateUser(username, &id);
2464 #ifdef AFS_ID_TO_NAME
2465 StringCbCopyN( username_copy, sizeof(username_copy),
2466 username, sizeof(username_copy) - 1);
2467 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2468 #endif /* AFS_ID_TO_NAME */
2471 #endif /* ALLOW_REGISTER */
2477 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
2482 ret = decode_Ticket(v5cred->ticket.data, v5cred->ticket.length,
2485 StringCbCopy(dest, destlen, ticket.realm);
2487 free_Ticket(&ticket);
2493 krb5_context alt_context,
2498 int lifetime, /* unused parameter */
2503 struct ktc_principal aserver;
2504 struct ktc_principal aclient;
2505 char realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2506 char realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2507 char local_cell[CELL_MAXNAMELEN+1];
2508 char Dmycell[CELL_MAXNAMELEN+1];
2509 struct ktc_token atoken;
2510 struct ktc_token btoken;
2511 struct afsconf_cell ak_cellconfig; /* General information about the cell */
2512 char RealmName[128];
2514 char ServiceName[128];
2517 krb5_context context = NULL;
2518 krb5_ccache cc = NULL;
2520 krb5_creds * k5creds = NULL;
2521 krb5_error_code code;
2522 krb5_principal client_principal = NULL;
2523 krb5_data * k5data = NULL;
2524 unsigned int retry = 0;
2527 memset(HostName, '\0', sizeof(HostName));
2528 gethostname(HostName, sizeof(HostName));
2529 if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2530 if ( IsDebuggerPresent() )
2531 OutputDebugString("Unable to retrieve AFSD Service Status\n");
2534 if (CurrentState != SERVICE_RUNNING) {
2535 if ( IsDebuggerPresent() )
2536 OutputDebugString("AFSD Service NOT RUNNING\n");
2540 memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
2541 memset(RealmName, '\0', sizeof(RealmName));
2542 memset(CellName, '\0', sizeof(CellName));
2543 memset(ServiceName, '\0', sizeof(ServiceName));
2544 memset(realm_of_user, '\0', sizeof(realm_of_user));
2545 memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2546 if (cell && cell[0])
2547 StringCbCopyN( Dmycell, sizeof(Dmycell),
2548 cell, sizeof(Dmycell) - 1);
2550 memset(Dmycell, '\0', sizeof(Dmycell));
2552 // NULL or empty cell returns information on local cell
2553 if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2555 // KFW_AFS_error(rc, "get_cellconfig()");
2559 if ( alt_context ) {
2560 context = alt_context;
2562 code = krb5_init_context(&context);
2563 if (code) goto cleanup;
2569 code = krb5_cc_default(context, &cc);
2574 memset(&increds, 0, sizeof(increds));
2576 code = krb5_cc_get_principal(context, cc, &client_principal);
2578 if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2580 OutputDebugString("Principal Not Found for ccache\n");
2585 if (!KFW_accept_dotted_usernames()) {
2587 /* look for client principals which cannot be distinguished
2588 * from Kerberos 4 multi-component principal names
2590 comp = krb5_principal_get_comp_string(context,client_principal,0);
2591 if (strchr(comp, '.') != NULL) {
2592 OutputDebugString("Illegal Principal name contains dot in first component\n");
2593 rc = KRB5KRB_ERR_GENERIC;
2598 StringCbCopy(realm_of_user, sizeof(realm_of_user),
2599 krb5_principal_get_realm(context, client_principal));
2601 StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
2602 afs_realm_of_cell(context, &ak_cellconfig),
2603 sizeof(realm_of_cell) - 1);
2605 if (strlen(service) == 0)
2606 StringCbCopy( ServiceName, sizeof(ServiceName), "afs");
2608 StringCbCopyN( ServiceName, sizeof(ServiceName),
2609 service, sizeof(ServiceName) - 1);
2611 if (strlen(cell) == 0)
2612 StringCbCopyN( CellName, sizeof(CellName),
2613 local_cell, sizeof(CellName) - 1);
2615 StringCbCopyN( CellName, sizeof(CellName),
2616 cell, sizeof(CellName) - 1);
2618 /* This is for Kerberos v4 only */
2619 if (strlen(realm) == 0)
2620 StringCbCopyN( RealmName, sizeof(RealmName),
2621 realm_of_cell, sizeof(RealmName) - 1);
2623 StringCbCopyN( RealmName, sizeof(RealmName),
2624 realm, sizeof(RealmName) - 1);
2626 code = KRB5KRB_ERR_GENERIC;
2628 increds.client = client_principal;
2629 increds.times.endtime = 0;
2630 /* Ask for DES since that is what V4 understands */
2631 increds.session.keytype = ENCTYPE_DES_CBC_CRC;
2633 /* ALWAYS first try service/cell@CLIENT_REALM */
2634 if (code = krb5_build_principal(context, &increds.server,
2635 (int)strlen(realm_of_user),
2644 if ( IsDebuggerPresent() ) {
2645 char * cname, *sname;
2646 krb5_unparse_name(context, increds.client, &cname);
2647 krb5_unparse_name(context, increds.server, &sname);
2648 OutputDebugString("Getting tickets for \"");
2649 OutputDebugString(cname);
2650 OutputDebugString("\" and service \"");
2651 OutputDebugString(sname);
2652 OutputDebugString("\"\n");
2653 krb5_free_unparsed_name(context,cname);
2654 krb5_free_unparsed_name(context,sname);
2657 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2660 * The client's realm is a local realm for the cell.
2661 * Save it so that later the pts registration will not
2664 StringCbCopyN(realm_of_cell, sizeof(realm_of_cell),
2665 realm_of_user, sizeof(realm_of_cell) - 1);
2668 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2669 code == KRB5_ERR_HOST_REALM_UNKNOWN ||
2670 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2671 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2673 * If there was a specific realm we are supposed to try
2676 if (strlen(realm) != 0) {
2677 /* service/cell@REALM */
2679 code = krb5_build_principal(context, &increds.server,
2685 if ( IsDebuggerPresent() ) {
2686 char * cname, *sname;
2687 krb5_unparse_name(context, increds.client, &cname);
2688 krb5_unparse_name(context, increds.server, &sname);
2689 OutputDebugString("Getting tickets for \"");
2690 OutputDebugString(cname);
2691 OutputDebugString("\" and service \"");
2692 OutputDebugString(sname);
2693 OutputDebugString("\"\n");
2694 krb5_free_unparsed_name(context,cname);
2695 krb5_free_unparsed_name(context,sname);
2699 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2701 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2702 code == KRB5_ERR_HOST_REALM_UNKNOWN ||
2703 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2704 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2705 /* Or service@REALM */
2706 krb5_free_principal(context,increds.server);
2708 code = krb5_build_principal(context, &increds.server,
2714 if ( IsDebuggerPresent() ) {
2715 char * cname, *sname;
2716 krb5_unparse_name(context, increds.client, &cname);
2717 krb5_unparse_name(context, increds.server, &sname);
2718 DebugPrintf("Getting tickets for \"%s\" and service \"%s\"\n", cname, sname);
2719 krb5_free_unparsed_name(context,cname);
2720 krb5_free_unparsed_name(context,sname);
2724 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2728 /* we have a local realm for the cell */
2729 StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
2730 realm, sizeof(realm_of_cell) - 1);
2733 if (strcmp(realm_of_user, realm_of_cell)) {
2734 /* Then service/cell@CELL_REALM */
2735 krb5_free_principal(context,increds.server);
2737 code = krb5_build_principal(context, &increds.server,
2738 (int)strlen(realm_of_cell),
2743 if ( IsDebuggerPresent()) {
2744 char * cname, *sname;
2745 krb5_unparse_name(context, increds.client, &cname);
2746 krb5_unparse_name(context, increds.server, &sname);
2747 OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2748 OutputDebugString("Trying again: getting tickets for \"");
2749 OutputDebugString(cname);
2750 OutputDebugString("\" and service \"");
2751 OutputDebugString(sname);
2752 OutputDebugString("\"\n");
2753 krb5_free_unparsed_name(context,cname);
2754 krb5_free_unparsed_name(context,sname);
2758 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2760 if (!code && !strlen(realm_of_cell))
2761 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
2765 if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2766 code == KRB5_ERR_HOST_REALM_UNKNOWN ||
2767 code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2768 code == KRB5KRB_AP_ERR_MSG_TYPE) {
2769 /* Finally service@CELL_REALM */
2770 krb5_free_principal(context,increds.server);
2772 code = krb5_build_principal(context, &increds.server,
2773 (int)strlen(realm_of_cell),
2778 if ( IsDebuggerPresent() ) {
2779 char * cname, *sname;
2780 krb5_unparse_name(context, increds.client, &cname);
2781 krb5_unparse_name(context, increds.server, &sname);
2782 DebugPrintf("krb5_get_credentials() returned Service Principal Unknown\n"
2783 "Trying again: getting tickets for \"%s\" and service \"%s\"\n", cname, sname);
2784 krb5_free_unparsed_name(context,cname);
2785 krb5_free_unparsed_name(context,sname);
2789 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2790 if (!code && !strlen(realm_of_cell))
2791 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
2796 DebugPrintf("krb5_get_credentials returns: %d\n", code);
2800 /* This code inserts the entire K5 ticket into the token */
2801 memset(&aserver, '\0', sizeof(aserver));
2802 StringCbCopyN(aserver.name, sizeof(aserver.name),
2803 ServiceName, sizeof(aserver.name) - 1);
2804 StringCbCopyN(aserver.cell, sizeof(aserver.cell),
2805 CellName, sizeof(aserver.cell) - 1);
2807 memset(&atoken, '\0', sizeof(atoken));
2808 atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2809 atoken.startTime = k5creds->times.starttime;
2810 atoken.endTime = k5creds->times.endtime;
2811 memcpy(&atoken.sessionKey,
2812 k5creds->session.keyvalue.data,
2813 k5creds->session.keyvalue.length);
2814 atoken.ticketLen = k5creds->ticket.length;
2815 memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2818 rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2819 if ( IsDebuggerPresent() ) {
2821 StringCbPrintf(message, sizeof(message), "ktc_GetToken returns: %d\n", rc);
2822 OutputDebugString(message);
2824 if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2825 if ( rc == KTC_NOCM && retry < 20 ) {
2828 goto retry_gettoken5;
2833 if (atoken.kvno == btoken.kvno &&
2834 atoken.ticketLen == btoken.ticketLen &&
2835 !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2836 !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2838 /* Success - Nothing to do */
2842 // * Reset the "aclient" structure before we call ktc_SetToken.
2843 // * This structure was first set by the ktc_GetToken call when
2844 // * we were comparing whether identical tokens already existed.
2846 StringCbCopy(aclient.name, sizeof(aclient.name),
2847 krb5_principal_get_comp_string(context, k5creds->client, 0));
2849 if ( krb5_principal_get_num_comp(context, k5creds->client) > 1 ) {
2850 StringCbCat(aclient.name, sizeof(aclient.name), ".");
2851 StringCbCat(aclient.name, sizeof(aclient.name),
2852 krb5_principal_get_comp_string(context, k5creds->client, 1));
2854 aclient.instance[0] = '\0';
2856 StringCbCopyN(aclient.cell, sizeof(aclient.cell),
2857 realm_of_cell, sizeof(aclient.cell) - 1);
2859 /* For Khimaira, always append the realm name */
2860 StringCbCat(aclient.name, sizeof(aclient.name), "@");
2861 StringCbCat(aclient.name, sizeof(aclient.name),
2862 krb5_principal_get_realm(context, k5creds->client));
2864 GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
2865 if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
2866 ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
2867 &aclient, &aserver, &atoken);
2870 StringCbCopyN(aclient.smbname, sizeof(aclient.smbname),
2871 smbname, sizeof(aclient.smbname) - 1);
2873 aclient.smbname[0] = '\0';
2875 if ( IsDebuggerPresent() ) {
2877 StringCbPrintf(message, sizeof(message), "aclient.name: %s\n", aclient.name);
2878 OutputDebugString(message);
2879 StringCbPrintf(message, sizeof(message), "aclient.smbname: %s\n", aclient.smbname);
2880 OutputDebugString(message);
2883 rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
2886 if (client_principal)
2887 krb5_free_principal(context,client_principal);
2888 /* increds.client == client_principal */
2890 krb5_free_principal(context,increds.server);
2891 if (cc && (cc != alt_cc))
2892 krb5_cc_close(context, cc);
2893 if (context && (context != alt_context))
2894 krb5_free_context(context);
2895 if (ak_cellconfig.linkedCell)
2896 free(ak_cellconfig.linkedCell);
2898 return(rc? rc : code);
2901 /**************************************/
2902 /* afs_realm_of_cell(): */
2903 /**************************************/
2905 afs_realm_of_cell(krb5_context context, struct afsconf_cell *cellconfig)
2907 static char krbrlm[REALM_SZ+1]="";
2908 char ** realmlist=NULL;
2914 r = krb5_get_host_realm(context, cellconfig->hostName[0], &realmlist);
2915 if ( !r && realmlist && realmlist[0] ) {
2916 StringCbCopyN( krbrlm, sizeof(krbrlm),
2917 realmlist[0], sizeof(krbrlm) - 1);
2918 krb5_free_host_realm(context, realmlist);
2924 char *t = cellconfig->name;
2929 if (islower(c)) c=toupper(c);
2937 /**************************************/
2938 /* KFW_AFS_get_cellconfig(): */
2939 /**************************************/
2941 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
2944 char newcell[CELL_MAXNAMELEN+1];
2945 char linkedcell[CELL_MAXNAMELEN+1]="";
2947 local_cell[0] = (char)0;
2948 memset(cellconfig, 0, sizeof(*cellconfig));
2950 /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
2951 if (rc = cm_GetRootCellName(local_cell))
2956 if (strlen(cell) == 0)
2957 StringCbCopy(cell, CELL_MAXNAMELEN, local_cell);
2959 rc = cm_SearchCellRegistry(1, cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
2960 if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
2961 rc = cm_SearchCellFileEx(cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
2964 rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
2968 StringCbCopyN( cellconfig->name, sizeof(cellconfig->name),
2969 newcell, sizeof(cellconfig->name) - 1);
2971 cellconfig->linkedCell = strdup(linkedcell);
2976 /**************************************/
2977 /* get_cellconfig_callback(): */
2978 /**************************************/
2980 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep, unsigned short ipRank)
2982 struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
2984 cc->hostAddr[cc->numServers] = *addrp;
2985 StringCbCopyN( cc->hostName[cc->numServers], sizeof(cc->hostName[cc->numServers]),
2986 namep, sizeof(cc->hostName[cc->numServers]) - 1);
2992 /**************************************/
2993 /* KFW_AFS_error(): */
2994 /**************************************/
2996 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
2999 const char *errText;
3001 // Using AFS defines as error messages for now, until Transarc
3002 // gets back to me with "string" translations of each of these
3004 if (rc == KTC_ERROR)
3005 errText = "KTC_ERROR";
3006 else if (rc == KTC_TOOBIG)
3007 errText = "KTC_TOOBIG";
3008 else if (rc == KTC_INVAL)
3009 errText = "KTC_INVAL";
3010 else if (rc == KTC_NOENT)
3011 errText = "KTC_NOENT";
3012 else if (rc == KTC_PIOCTLFAIL)
3013 errText = "KTC_PIOCTLFAIL";
3014 else if (rc == KTC_NOPIOCTL)
3015 errText = "KTC_NOPIOCTL";
3016 else if (rc == KTC_NOCELL)
3017 errText = "KTC_NOCELL";
3018 else if (rc == KTC_NOCM)
3019 errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
3021 errText = "Unknown error!";
3023 StringCbPrintf(message, sizeof(message), "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3025 if ( IsDebuggerPresent() ) {
3026 OutputDebugString(message);
3027 OutputDebugString("\n");
3029 MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3035 LPSTR lpszMachineName,
3036 LPSTR lpszServiceName,
3037 DWORD *lpdwCurrentState)
3040 SC_HANDLE schSCManager = NULL;
3041 SC_HANDLE schService = NULL;
3042 DWORD fdwDesiredAccess = 0;
3043 SERVICE_STATUS ssServiceStatus = {0};
3046 *lpdwCurrentState = 0;
3048 fdwDesiredAccess = GENERIC_READ;
3050 schSCManager = OpenSCManager(lpszMachineName,
3054 if(schSCManager == NULL)
3056 hr = GetLastError();
3060 schService = OpenService(schSCManager,
3064 if(schService == NULL)
3066 hr = GetLastError();
3070 fRet = QueryServiceStatus(schService,
3075 hr = GetLastError();
3079 *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3083 CloseServiceHandle(schService);
3084 CloseServiceHandle(schSCManager);
3089 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3091 krb5_context context = NULL;
3092 krb5_ccache cc = NULL;
3093 krb5_error_code code;
3095 const char * realm = NULL;
3096 krb5_principal principal = NULL;
3097 char * pname = NULL;
3098 char password[PROBE_PASSWORD_LEN+1];
3099 BOOL serverReachable = 0;
3101 code = krb5_init_context(&context);
3102 if (code) goto cleanup;
3105 realm = afs_realm_of_cell(context, cellconfig); // do not free
3107 code = krb5_build_principal(context, &principal, (int)strlen(realm),
3108 realm, PROBE_USERNAME, NULL, NULL);
3109 if ( code ) goto cleanup;
3111 code = KFW_get_ccache(context, principal, &cc);
3112 if ( code ) goto cleanup;
3114 code = krb5_unparse_name(context, principal, &pname);
3115 if ( code ) goto cleanup;
3117 pwdata.data = password;
3118 pwdata.length = PROBE_PASSWORD_LEN;
3119 krb5_c_random_make_octets(context, &pwdata);
3122 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3123 if (password[i] == '\0')
3126 password[PROBE_PASSWORD_LEN] = '\0';
3128 code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3138 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3139 case KRB5KDC_ERR_CLIENT_REVOKED:
3140 case KRB5KDC_ERR_CLIENT_NOTYET:
3141 case KRB5KDC_ERR_PREAUTH_FAILED:
3142 case KRB5KDC_ERR_PREAUTH_REQUIRED:
3143 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3144 serverReachable = TRUE;
3147 serverReachable = FALSE;
3152 krb5_free_unparsed_name(context,pname);
3154 krb5_free_principal(context,principal);
3156 krb5_cc_close(context,cc);
3158 krb5_free_context(context);
3160 return serverReachable;
3164 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3166 krb5_context context = NULL;
3167 krb5_error_code code;
3168 krb5_ccache mslsa_ccache=NULL;
3169 krb5_principal princ = NULL;
3170 char * pname = NULL;
3173 if (!KFW_is_available())
3176 if (code = krb5_init_context(&context))
3179 if (code = krb5_cc_resolve(context, "MSLSA:", &mslsa_ccache))
3182 if (code = krb5_cc_get_principal(context, mslsa_ccache, &princ))
3185 if (code = krb5_unparse_name(context, princ, &pname))
3188 if ( strlen(pname) < *dwSize ) {
3189 StringCbCopyN(szUser, *dwSize, pname, (*dwSize) - 1);
3192 *dwSize = (DWORD)strlen(pname);
3196 krb5_free_unparsed_name(context, pname);
3199 krb5_free_principal(context, princ);
3202 krb5_cc_close(context, mslsa_ccache);
3205 krb5_free_context(context);
3210 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3212 // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3213 PSID pSystemSID = NULL;
3214 DWORD SystemSIDlength = 0, UserSIDlength = 0;
3215 PACL ccacheACL = NULL;
3216 DWORD ccacheACLlength = 0;
3217 PTOKEN_USER pTokenUser = NULL;
3226 /* Get System SID */
3227 if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3233 SystemSIDlength = GetLengthSid(pSystemSID);
3234 ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3235 + SystemSIDlength - sizeof(DWORD);
3238 if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3240 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3241 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3243 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3248 UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3250 ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
3255 ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3260 InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3261 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3262 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3265 AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3266 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3267 pTokenUser->User.Sid);
3268 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3269 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3274 gle = GetLastError();
3275 if (gle != ERROR_NO_TOKEN)
3278 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3279 OWNER_SECURITY_INFORMATION,
3280 pTokenUser->User.Sid,
3284 gle = GetLastError();
3285 if (gle != ERROR_NO_TOKEN)
3289 if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3290 DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3295 gle = GetLastError();
3296 if (gle != ERROR_NO_TOKEN)
3303 LocalFree(pSystemSID);
3305 LocalFree(pTokenUser);
3307 LocalFree(ccacheACL);
3312 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3315 DWORD dwSize = size-1; /* leave room for nul */
3318 if (!hUserToken || !newfilename || size <= 0)
3321 *newfilename = '\0';
3323 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3324 if ( !dwLen || dwLen > dwSize )
3325 dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3326 if ( !dwLen || dwLen > dwSize )
3329 newfilename[dwSize] = '\0';
3334 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3336 char filename[MAX_PATH] = "";
3338 char cachename[MAX_PATH + 8] = "FILE:";
3339 krb5_context context = NULL;
3340 krb5_error_code code;
3341 krb5_principal princ = NULL;
3342 krb5_ccache cc = NULL;
3343 krb5_ccache ncc = NULL;
3345 if (!user || !szLogonId)
3348 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3349 if ( count > sizeof(filename) || count == 0 ) {
3350 GetWindowsDirectory(filename, sizeof(filename));
3353 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3356 StringCbCat( filename, sizeof(filename), "\\");
3357 StringCbCat( filename, sizeof(filename), szLogonId);
3359 StringCbCat( cachename, sizeof(cachename), filename);
3361 DeleteFile(filename);
3363 code = krb5_init_context(&context);
3364 if (code) goto cleanup;
3366 code = krb5_parse_name(context, user, &princ);
3367 if (code) goto cleanup;
3369 code = KFW_get_ccache(context, princ, &cc);
3370 if (code) goto cleanup;
3372 code = krb5_cc_resolve(context, cachename, &ncc);
3373 if (code) goto cleanup;
3375 code = krb5_cc_initialize(context, ncc, princ);
3376 if (code) goto cleanup;
3378 code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3379 if (code) goto cleanup;
3381 code = krb5_cc_copy_creds(context,cc,ncc);
3385 krb5_cc_close(context, cc);
3389 krb5_cc_close(context, ncc);
3393 krb5_free_principal(context, princ);
3398 krb5_free_context(context);
3402 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3404 char cachename[MAX_PATH + 8] = "FILE:";
3405 krb5_context context = NULL;
3406 krb5_error_code code;
3407 krb5_principal princ = NULL;
3408 krb5_ccache cc = NULL;
3409 krb5_ccache ncc = NULL;
3415 if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3418 code = krb5_init_context(&context);
3421 StringCbCat( cachename, sizeof(cachename), filename);
3423 code = krb5_cc_resolve(context, cachename, &cc);
3424 if (code) goto cleanup;
3426 code = krb5_cc_get_principal(context, cc, &princ);
3428 code = krb5_cc_default(context, &ncc);
3430 code = krb5_cc_initialize(context, ncc, princ);
3433 code = krb5_cc_copy_creds(context,cc,ncc);
3436 krb5_cc_close(context, ncc);
3440 retval=0; /* success */
3444 krb5_cc_close(context, cc);
3448 DeleteFile(filename);
3451 krb5_free_principal(context, princ);
3456 krb5_free_context(context);
3461 /* We are including this
3463 /* Ticket lifetime. This defines the table used to lookup lifetime for the
3464 fixed part of rande of the one byte lifetime field. Values less than 0x80
3465 are intrpreted as the number of 5 minute intervals. Values from 0x80 to
3466 0xBF should be looked up in this table. The value of 0x80 is the same using
3467 both methods: 10 and two-thirds hours . The lifetime of 0xBF is 30 days.
3468 The intervening values of have a fixed ratio of roughly 1.06914. The value
3469 oxFF is defined to mean a ticket has no expiration time. This should be
3470 used advisedly since individual servers may impose defacto upperbounds on
3471 ticket lifetimes. */
3473 #define TKTLIFENUMFIXED 64
3474 #define TKTLIFEMINFIXED 0x80
3475 #define TKTLIFEMAXFIXED 0xBF
3476 #define TKTLIFENOEXPIRE 0xFF
3477 #define MAXTKTLIFETIME (30*24*3600) /* 30 days */
3479 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3480 38400, /* 10.67 hours, 0.44 days */
3481 41055, /* 11.40 hours, 0.48 days */
3482 43894, /* 12.19 hours, 0.51 days */
3483 46929, /* 13.04 hours, 0.54 days */
3484 50174, /* 13.94 hours, 0.58 days */
3485 53643, /* 14.90 hours, 0.62 days */
3486 57352, /* 15.93 hours, 0.66 days */
3487 61318, /* 17.03 hours, 0.71 days */
3488 65558, /* 18.21 hours, 0.76 days */
3489 70091, /* 19.47 hours, 0.81 days */
3490 74937, /* 20.82 hours, 0.87 days */
3491 80119, /* 22.26 hours, 0.93 days */
3492 85658, /* 23.79 hours, 0.99 days */
3493 91581, /* 25.44 hours, 1.06 days */
3494 97914, /* 27.20 hours, 1.13 days */
3495 104684, /* 29.08 hours, 1.21 days */
3496 111922, /* 31.09 hours, 1.30 days */
3497 119661, /* 33.24 hours, 1.38 days */
3498 127935, /* 35.54 hours, 1.48 days */
3499 136781, /* 37.99 hours, 1.58 days */
3500 146239, /* 40.62 hours, 1.69 days */
3501 156350, /* 43.43 hours, 1.81 days */
3502 167161, /* 46.43 hours, 1.93 days */
3503 178720, /* 49.64 hours, 2.07 days */
3504 191077, /* 53.08 hours, 2.21 days */
3505 204289, /* 56.75 hours, 2.36 days */
3506 218415, /* 60.67 hours, 2.53 days */
3507 233517, /* 64.87 hours, 2.70 days */
3508 249664, /* 69.35 hours, 2.89 days */
3509 266926, /* 74.15 hours, 3.09 days */
3510 285383, /* 79.27 hours, 3.30 days */
3511 305116, /* 84.75 hours, 3.53 days */
3512 326213, /* 90.61 hours, 3.78 days */
3513 348769, /* 96.88 hours, 4.04 days */
3514 372885, /* 103.58 hours, 4.32 days */
3515 398668, /* 110.74 hours, 4.61 days */
3516 426234, /* 118.40 hours, 4.93 days */
3517 455705, /* 126.58 hours, 5.27 days */
3518 487215, /* 135.34 hours, 5.64 days */
3519 520904, /* 144.70 hours, 6.03 days */
3520 556921, /* 154.70 hours, 6.45 days */
3521 595430, /* 165.40 hours, 6.89 days */
3522 636601, /* 176.83 hours, 7.37 days */
3523 680618, /* 189.06 hours, 7.88 days */
3524 727680, /* 202.13 hours, 8.42 days */
3525 777995, /* 216.11 hours, 9.00 days */
3526 831789, /* 231.05 hours, 9.63 days */
3527 889303, /* 247.03 hours, 10.29 days */
3528 950794, /* 264.11 hours, 11.00 days */
3529 1016537, /* 282.37 hours, 11.77 days */
3530 1086825, /* 301.90 hours, 12.58 days */
3531 1161973, /* 322.77 hours, 13.45 days */
3532 1242318, /* 345.09 hours, 14.38 days */
3533 1328218, /* 368.95 hours, 15.37 days */
3534 1420057, /* 394.46 hours, 16.44 days */
3535 1518247, /* 421.74 hours, 17.57 days */
3536 1623226, /* 450.90 hours, 18.79 days */
3537 1735464, /* 482.07 hours, 20.09 days */
3538 1855462, /* 515.41 hours, 21.48 days */
3539 1983758, /* 551.04 hours, 22.96 days */
3540 2120925, /* 589.15 hours, 24.55 days */
3541 2267576, /* 629.88 hours, 26.25 days */
3542 2424367, /* 673.44 hours, 28.06 days */
3544 }; /* 720.00 hours, 30.00 days */
3546 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3547 * returns the corresponding end time. There are four simple cases to be
3548 * handled. The first is a life of 0xff, meaning no expiration, and results in
3549 * an end time of 0xffffffff. The second is when life is less than the values
3550 * covered by the table. In this case, the end time is the start time plus the
3551 * number of 5 minute intervals specified by life. The third case returns
3552 * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED. The
3553 * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3554 * table to extract the lifetime in seconds, which is added to start to produce
3558 life_to_time(afs_uint32 start, unsigned char life)
3562 if (life == TKTLIFENOEXPIRE)
3564 if (life < TKTLIFEMINFIXED)
3565 return start + life * 5 * 60;
3566 if (life > TKTLIFEMAXFIXED)
3567 return start + MAXTKTLIFETIME;
3568 realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3569 return start + realLife;
3572 /* time_to_life - takes start and end times for the ticket and returns a
3573 * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3574 * lifetimes above 127*5minutes. First, the special case of (end ==
3575 * 0xffffffff) is handled to mean no expiration. Then negative lifetimes and
3576 * those greater than the maximum ticket lifetime are rejected. Then lifetimes
3577 * less than the first table entry are handled by rounding the requested
3578 * lifetime *up* to the next 5 minute interval. The final step is to search
3579 * the table for the smallest entry *greater than or equal* to the requested
3580 * entry. The actual code is prepared to handle the case where the table is
3581 * unordered but that it an unnecessary frill. */
3583 static unsigned char
3584 time_to_life(afs_uint32 start, afs_uint32 end)
3586 int lifetime = end - start;
3590 if (end == NEVERDATE)
3591 return TKTLIFENOEXPIRE;
3592 if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
3594 if (lifetime < tkt_lifetimes[0])
3595 return (lifetime + 5 * 60 - 1) / (5 * 60);
3597 best = MAXKTCTICKETLIFETIME;
3598 for (i = 0; i < TKTLIFENUMFIXED; i++)
3599 if (tkt_lifetimes[i] >= lifetime) {
3600 int diff = tkt_lifetimes[i] - lifetime;
3608 return best_i + TKTLIFEMINFIXED;
3611 DWORD KFW_get_default_mslsa_import(krb5_context context)
3613 static const char * lsh_settings_key = "";
3614 static const char * lsh_mslsa_value = "";
3620 rc = RegOpenKeyEx(HKEY_CURRENT_USER, lsh_settings_key, 0, KEY_QUERY_VALUE, &hKey);
3624 dwCount = sizeof(DWORD);
3625 rc = RegQueryValueEx(hKey, lsh_mslsa_value, 0, 0, (LPBYTE) &import, &dwCount);
3631 rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lsh_settings_key, 0, KEY_QUERY_VALUE, &hKey);
3635 dwCount = sizeof(DWORD);
3636 rc = RegQueryValueEx(hKey, lsh_mslsa_value, 0, 0, (LPBYTE) &import, &dwCount);
3642 DWORD KFW_get_default_lifetime(krb5_context context, const char * realm)
3644 static const char * lifetime_val_name = "ticket_lifetime";
3647 krb5_appdefault_time(context, "aklog", realm, lifetime_val_name, 0, &t);
3650 t = krb5_config_get_time_default(context, NULL, 0,
3651 "realms", realm, lifetime_val_name, NULL);
3654 t = krb5_config_get_time_default(context, NULL, 0,
3655 "libdefaults", lifetime_val_name, NULL);