7bcb71233cc437fd8b8fd022f247cf09f8a98aff
[openafs.git] / src / WINNT / afsd / afskfw.c
1 /*
2  * Copyright (c) 2004, 2005, 2006, 2007, 2008 Secure Endpoints Inc.
3  * Copyright (c) 2003 SkyRope, LLC
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
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.
17  *
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.
29  *
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.
33  *
34  * Copyright (c) 2003,2004 by the Massachusetts Institute of Technology.
35  * All rights reserved.
36  *
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.
41  *
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.
55  *
56  */
57
58 #undef  USE_KRB4
59 #undef  USE_KRB524
60 #define USE_MS2MIT 1
61
62 #include <afsconfig.h>
63 #include <afs/param.h>
64 #include <roken.h>
65
66 #include <osilog.h>
67 #include <afs/ptserver.h>
68 #include <afs/ptuser.h>
69 #include <afs/auth.h>
70 #include <afs/com_err.h>
71 #include <rx/rxkad.h>
72 #include <WINNT\afsreg.h>
73 #include "cm.h"
74
75 #include "afskfw.h"
76 #include "afskfw-int.h"
77 #include <userenv.h>
78 #include <strsafe.h>
79
80 #include <Sddl.h>
81 #include <Aclapi.h>
82
83 #include <krbcompat_delayload.h>
84
85 #ifndef KRB5_TC_OPENCLOSE
86 #define KRB5_TC_OPENCLOSE 0x00000001
87 #endif
88
89 /*
90  * TIMING _____________________________________________________________________
91  *
92  */
93
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
98
99 #define c100ns1SECOND        (LONGLONG)10000000
100 #define cmsec1SECOND         1000
101 #define cmsec1MINUTE         60000
102 #define csec1MINUTE          60
103
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[]);
111
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;
118
119 #ifdef USE_LEASH
120 #define DEFAULT_LIFETIME pLeash_get_default_lifetime()
121 #else
122 #define DEFAULT_LIFETIME (24 * 60)
123 #endif
124
125 void
126 DebugPrintf(const char * fmt, ...)
127 {
128     if (IsDebuggerPresent()) {
129         va_list vl;
130         char buf[1024];
131
132         va_start(vl, fmt);
133         StringCbVPrintfA(buf, sizeof(buf), fmt, vl);
134         OutputDebugStringA(buf);
135         va_end(vl);
136     }
137 }
138
139 void
140 KFW_initialize(void)
141 {
142     static int inited = 0;
143
144     if ( !inited ) {
145         char mutexName[MAX_PATH];
146         HANDLE hMutex = NULL;
147
148         StringCbPrintf( mutexName, sizeof(mutexName), "AFS KFW Init pid=%d", getpid());
149
150         hMutex = CreateMutex( NULL, TRUE, mutexName );
151         if ( GetLastError() == ERROR_ALREADY_EXISTS ) {
152             if ( WaitForSingleObject( hMutex, INFINITE ) != WAIT_OBJECT_0 ) {
153                 return;
154             }
155         }
156         if ( !inited ) {
157             inited = 1;
158
159             DelayLoadHeimdal();
160
161             if ( KFW_is_available() ) {
162                 char rootcell[CELL_MAXNAMELEN+1];
163 #ifdef USE_MS2MIT
164                 KFW_import_windows_lsa();
165 #endif /* USE_MS2MIT */
166                 KFW_import_ccache_data();
167                 KFW_AFS_renew_expiring_tokens();
168
169                 /* WIN32 NOTE: no way to get max chars */
170                 if (!cm_GetRootCellName(rootcell))
171                     KFW_AFS_renew_token_for_cell(rootcell);
172             }
173         }
174         ReleaseMutex(hMutex);
175         CloseHandle(hMutex);
176
177         initialize_KTC_error_table();
178         initialize_PT_error_table();
179     }
180 }
181
182 void
183 KFW_cleanup(void)
184 {
185 }
186
187 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
188 static int IsWow64()
189 {
190     static int init = TRUE;
191     static int bIsWow64 = FALSE;
192
193     if (init) {
194         HMODULE hModule;
195         LPFN_ISWOW64PROCESS fnIsWow64Process = NULL;
196
197         hModule = GetModuleHandle(TEXT("kernel32"));
198         if (hModule) {
199             fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hModule, "IsWow64Process");
200
201             if (NULL != fnIsWow64Process)
202             {
203                 if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
204                 {
205                     // on error, assume FALSE.
206                     // in other words, do nothing.
207                 }
208             }
209             FreeLibrary(hModule);
210         }
211         init = FALSE;
212     }
213     return bIsWow64;
214 }
215
216 int
217 KFW_accept_dotted_usernames(void)
218 {
219     HKEY parmKey;
220     DWORD code, len;
221     DWORD value = 1;
222
223     code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
224                         0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
225     if (code == ERROR_SUCCESS) {
226         len = sizeof(value);
227         code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
228                                (BYTE *) &value, &len);
229         RegCloseKey(parmKey);
230     }
231     if (code != ERROR_SUCCESS) {
232         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
233                             0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
234         if (code == ERROR_SUCCESS) {
235             len = sizeof(value);
236             code = RegQueryValueEx(parmKey, "AcceptDottedPrincipalNames", NULL, NULL,
237                                    (BYTE *) &value, &len);
238             RegCloseKey (parmKey);
239         }
240     }
241     return value;
242 }
243
244
245 int
246 KFW_use_krb524(void)
247 {
248     return 0;
249 }
250
251 int
252 KFW_is_available(void)
253 {
254     HKEY parmKey;
255     DWORD code, len;
256     DWORD enableKFW = 1;
257
258     code = RegOpenKeyEx(HKEY_CURRENT_USER, AFSREG_USER_OPENAFS_SUBKEY,
259                         0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
260     if (code == ERROR_SUCCESS) {
261         len = sizeof(enableKFW);
262         code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
263                                (BYTE *) &enableKFW, &len);
264         RegCloseKey (parmKey);
265     }
266
267     if (code != ERROR_SUCCESS) {
268         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_OPENAFS_SUBKEY,
269                             0, (IsWow64()?KEY_WOW64_64KEY:0)|KEY_QUERY_VALUE, &parmKey);
270         if (code == ERROR_SUCCESS) {
271             len = sizeof(enableKFW);
272             code = RegQueryValueEx(parmKey, "EnableKFW", NULL, NULL,
273                                    (BYTE *) &enableKFW, &len);
274             RegCloseKey (parmKey);
275         }
276     }
277
278     if ( !enableKFW )
279         return FALSE;
280
281     KFW_initialize();
282
283     /* If this is non-zero, then some Kerberos library was loaded. */
284     return (krb5_init_context != NULL);
285 }
286
287 int
288 KRB5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
289            int FreeContextFlag, krb5_context * context,
290            krb5_ccache * cache)
291 {
292     char message[256];
293     const char *errText;
294     int krb5Error = ((int)(rc & 255));
295
296     errText = krb5_get_error_message(*context, rc);
297     StringCbPrintf(message, sizeof(message),
298                    "%s\n(Kerberos error %ld)\n\n%s failed",
299                    errText,
300                    krb5Error,
301                    FailedFunctionName);
302     krb5_free_error_message(*context, (char *)errText);
303
304     DebugPrintf("%s", message);
305
306     MessageBox(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
307                MB_TASKMODAL |
308                MB_SETFOREGROUND);
309
310     if (FreeContextFlag == 1) {
311
312         if (context && *context != NULL) {
313
314             if (cache && *cache != NULL) {
315                 krb5_cc_close(*context, *cache);
316                 *cache = NULL;
317             }
318
319             krb5_free_context(*context);
320             *context = NULL;
321         }
322     }
323
324     return rc;
325 }
326
327 void
328 KFW_AFS_update_princ_ccache_data(krb5_context context, krb5_ccache cc, int lsa)
329 {
330     struct principal_ccache_data * next = princ_cc_data;
331     krb5_principal principal = 0;
332     char * pname = NULL;
333     const char * ccname = NULL;
334     const char * cctype = NULL;
335     char * ccfullname = NULL;
336     krb5_error_code code = 0;
337     krb5_error_code cc_code = 0;
338     krb5_cc_cursor cur;
339     krb5_creds creds;
340     krb5_flags flags=0;
341     krb5_timestamp now;
342     size_t len;
343
344     if (context == 0 || cc == 0)
345         return;
346
347     code = krb5_cc_get_principal(context, cc, &principal);
348     if ( code ) return;
349
350     code = krb5_unparse_name(context, principal, &pname);
351     if ( code ) goto cleanup;
352
353     ccname = krb5_cc_get_name(context, cc);
354     if (!ccname) goto cleanup;
355
356     cctype = krb5_cc_get_type(context, cc);
357     if (!cctype) goto cleanup;
358
359     len = strlen(ccname) + strlen(cctype) + 2;
360     ccfullname = malloc(len);
361     if (!ccfullname) goto cleanup;
362
363     StringCbPrintf(ccfullname, len, "%s:%s", cctype, ccname);
364
365     // Search the existing list to see if we have a match
366     if ( next ) {
367         for ( ; next ; next = next->next ) {
368             if ( !strcmp(next->principal,pname) && !strcmp(next->ccache_name, ccfullname) )
369                 break;
370         }
371     }
372
373     // If not, match add a new node to the beginning of the list and assign init it
374     if ( !next ) {
375         next = (struct principal_ccache_data *) malloc(sizeof(struct principal_ccache_data));
376         next->next = princ_cc_data;
377         princ_cc_data = next;
378         next->principal = _strdup(pname);
379         next->ccache_name = ccfullname;
380         ccfullname = NULL;
381         next->from_lsa = lsa;
382         next->expired = 1;
383         next->expiration_time = 0;
384         next->renew = 0;
385     }
386
387     flags = 0;  // turn off OPENCLOSE mode
388     code = krb5_cc_set_flags(context, cc, flags);
389     if ( code ) goto cleanup;
390
391     code = krb5_timeofday(context, &now);
392
393     cc_code = krb5_cc_start_seq_get(context, cc, &cur);
394
395     while (!(cc_code = krb5_cc_next_cred(context, cc, &cur, &creds))) {
396         if ( creds.flags.b.initial) {
397             int valid;
398             // we found the ticket we are looking for
399             // check validity of timestamp
400             // We add a 5 minutes fudge factor to compensate for potential
401             // clock skew errors between the KDC and client OS
402
403             valid = ((creds.times.starttime > 0) &&
404                      now >= (creds.times.starttime - 300) &&
405                      now < (creds.times.endtime + 300) &&
406                      !creds.flags.b.invalid);
407
408             if ( next->from_lsa) {
409                 next->expired = 0;
410                 next->expiration_time = creds.times.endtime;
411                 next->renew = 1;
412             } else if ( valid ) {
413                 next->expired = 0;
414                 next->expiration_time = creds.times.endtime;
415                 next->renew = (creds.times.renew_till > creds.times.endtime) &&
416                     creds.flags.b.renewable;
417             } else {
418                 next->expired = 1;
419                 next->expiration_time = 0;
420                 next->renew = 0;
421             }
422
423             krb5_free_cred_contents(context, &creds);
424             cc_code = KRB5_CC_END;
425             break;
426         }
427         krb5_free_cred_contents(context, &creds);
428     }
429
430     if (cc_code == KRB5_CC_END) {
431         code = krb5_cc_end_seq_get(context, cc, &cur);
432         if (code) goto cleanup;
433     }
434
435   cleanup:
436     flags = KRB5_TC_OPENCLOSE;  //turn on OPENCLOSE
437     code = krb5_cc_set_flags(context, cc, flags);
438
439     if ( ccfullname)
440         free(ccfullname);
441     if ( pname )
442         krb5_free_unparsed_name(context,pname);
443     if ( principal )
444         krb5_free_principal(context,principal);
445 }
446
447 int
448 KFW_AFS_find_ccache_for_principal(krb5_context context, char * principal,
449                                   char **ccache, int valid_only)
450 {
451     struct principal_ccache_data * next = princ_cc_data;
452     char * response = NULL;
453
454     if ( !principal || !ccache )
455         return 0;
456
457     while ( next ) {
458         if ( (!valid_only || !next->expired) && !strcmp(next->principal, principal) ) {
459             if (response) {
460                 // we always want to prefer the MS Kerberos LSA cache or
461                 // the cache afscreds created specifically for the principal
462                 // if the current entry is either one, drop the previous find
463                 if ( next->from_lsa || !strcmp(next->ccache_name, principal) )
464                     free(response);
465             }
466             response = _strdup(next->ccache_name);
467             // MS Kerberos LSA is our best option so use it and quit
468             if ( next->from_lsa )
469                 break;
470         }
471         next = next->next;
472     }
473
474     if ( response ) {
475         *ccache = response;
476         return 1;
477     }
478     return 0;
479 }
480
481 void
482 KFW_AFS_delete_princ_ccache_data(krb5_context context, char * pname, char * ccname)
483 {
484     struct principal_ccache_data ** next = &princ_cc_data;
485
486     if ( !pname && !ccname )
487         return;
488
489     while ( (*next) ) {
490         if ( !strcmp((*next)->principal,pname) ||
491              !strcmp((*next)->ccache_name,ccname) ) {
492             void * temp;
493             free((*next)->principal);
494             free((*next)->ccache_name);
495             temp = (*next);
496             (*next) = (*next)->next;
497             free(temp);
498         }
499     }
500 }
501
502 void
503 KFW_AFS_update_cell_princ_map(krb5_context context, char * cell, char *pname, int active)
504 {
505     struct cell_principal_map * next = cell_princ_map;
506
507     // Search the existing list to see if we have a match
508     if ( next ) {
509         for ( ; next ; next = next->next ) {
510             if ( !strcmp(next->cell, cell) ) {
511                 if ( !strcmp(next->principal,pname) ) {
512                     next->active = active;
513                                         break;
514                 } else {
515                     // OpenAFS currently has a restriction of one active token per cell
516                     // Therefore, whenever we update the table with a new active cell we
517                     // must mark all of the other principal to cell entries as inactive.
518                     if (active)
519                         next->active = 0;
520                 }
521             }
522         }
523     }
524
525     // If not, match add a new node to the beginning of the list and assign init it
526     if ( !next ) {
527         next = (struct cell_principal_map *) malloc(sizeof(struct cell_principal_map));
528         next->next = cell_princ_map;
529         cell_princ_map = next;
530         next->principal = _strdup(pname);
531         next->cell = _strdup(cell);
532         next->active = active;
533     }
534 }
535
536 void
537 KFW_AFS_delete_cell_princ_maps(krb5_context context, char * pname, char * cell)
538 {
539     struct cell_principal_map ** next = &cell_princ_map;
540
541     if ( !pname && !cell )
542         return;
543
544     while ( (*next) ) {
545         if ( !strcmp((*next)->principal,pname) ||
546              !strcmp((*next)->cell,cell) ) {
547             void * temp;
548             free((*next)->principal);
549             free((*next)->cell);
550             temp = (*next);
551             (*next) = (*next)->next;
552             free(temp);
553         }
554     }
555 }
556
557 // Returns (if possible) a principal which has been known in
558 // the past to have been used to obtain tokens for the specified
559 // cell.
560 // TODO: Attempt to return one which has not yet expired by checking
561 // the principal/ccache data
562 int
563 KFW_AFS_find_principals_for_cell(krb5_context context, char * cell, char **principals[], int active_only)
564 {
565     struct cell_principal_map * next_map = cell_princ_map;
566     const char * princ = NULL;
567     int count = 0, i;
568
569     if ( !cell )
570         return 0;
571
572     while ( next_map ) {
573         if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
574             count++;
575         }
576         next_map = next_map->next;
577     }
578
579     if ( !principals || !count )
580         return count;
581
582     *principals = (char **) malloc(sizeof(char *) * count);
583     for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
584     {
585         if ( (!active_only || next_map->active) && !strcmp(next_map->cell,cell) ) {
586             (*principals)[i++] = _strdup(next_map->principal);
587         }
588     }
589     return count;
590 }
591
592 int
593 KFW_AFS_find_cells_for_princ(krb5_context context, char * pname, char **cells[], int active_only)
594 {
595     int     count = 0, i;
596     struct cell_principal_map * next_map = cell_princ_map;
597     const char * princ = NULL;
598
599     if ( !pname )
600         return 0;
601
602     while ( next_map ) {
603         if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
604             count++;
605         }
606         next_map = next_map->next;
607     }
608
609     if ( !cells )
610         return count;
611
612     *cells = (char **) malloc(sizeof(char *) * count);
613     for ( next_map = cell_princ_map, i=0 ; next_map && i<count; next_map = next_map->next )
614     {
615         if ( (!active_only || next_map->active) && !strcmp(next_map->principal,pname) ) {
616             (*cells)[i++] = _strdup(next_map->cell);
617         }
618     }
619     return count;
620 }
621
622 static void
623 escape_unsafe_principal_characters(const char * pname,
624                                    char ** new_name)
625 {
626     const char * src;
627     char * dest;
628     size_t len = 0;
629
630     /* Count first */
631     for (src = pname; *src != '\0'; ++len, ++src) {
632         if (*src == '\\' || *src == '#' || *src == '<' ||
633             *src == '>' || *src == ':' || *src == '"' ||
634             *src == '/' || *src == '|' || *src == '?' ||
635             *src == '*')
636             ++len;
637     }
638
639     ++len;
640
641     *new_name = (char *) malloc(len);
642
643     if (*new_name == NULL)
644         return;
645
646     for (src = pname, dest = *new_name; *src != '\0'; ++src) {
647         switch (*src) {
648         case '\\': *dest++ = '#'; *dest++ = 'b'; break;
649
650         case '#' : *dest++ = '#'; *dest++ = '#'; break;
651
652         case '<' : *dest++ = '#'; *dest++ = 'l'; break;
653
654         case '>' : *dest++ = '#'; *dest++ = 'g'; break;
655
656         case ':' : *dest++ = '#'; *dest++ = 'c'; break;
657
658         case '"' : *dest++ = '#'; *dest++ = 't'; break;
659
660         case '/' : *dest++ = '#'; *dest++ = 'f'; break;
661
662         case '|' : *dest++ = '#'; *dest++ = 'p'; break;
663
664         case '?' : *dest++ = '#'; *dest++ = 'q'; break;
665
666         case '*' : *dest++ = '#'; *dest++ = 'a'; break;
667
668         default: *dest++ = *src;
669         }
670     }
671
672     *dest++ = '\0';
673 }
674
675 static void
676 get_default_ccache_name_for_principal(krb5_context context, krb5_principal principal,
677                                       char ** cc_name)
678 {
679     char * pname = NULL;
680     char * epname = NULL;
681     krb5_error_code code;
682     size_t len = 0;
683     char temppath[MAX_PATH]="";
684
685     *cc_name = NULL;
686
687     code = krb5_unparse_name(context, principal, &pname);
688     if (code) goto cleanup;
689
690     escape_unsafe_principal_characters(pname, &epname);
691
692     len = strlen(epname);
693     len += 21;
694     *cc_name = (char *) malloc(len);
695
696     GetTempPathA(MAX_PATH, temppath);
697     StringCbPrintfA(*cc_name, len, "FILE:%skrb5cc_%s", temppath, epname);
698
699 cleanup:
700     if (pname)
701         krb5_free_unparsed_name(context, pname);
702
703     if (epname)
704         free(epname);
705
706     return;
707 }
708
709 static int
710 is_default_ccache_for_principal(krb5_context context, krb5_principal principal,
711                                 krb5_ccache cc)
712 {
713     const char * cc_name;
714     char * def_cc_name = NULL;
715     const char *bs_cc;
716     const char *bs_def_cc;
717     int is_default;
718
719     cc_name = krb5_cc_get_name(context, cc);
720
721     get_default_ccache_name_for_principal(context, principal, &def_cc_name);
722
723     is_default = (cc_name != NULL && def_cc_name != NULL &&
724
725                   (bs_cc = strrchr(cc_name, '\\')) != NULL &&
726
727                   (bs_def_cc = strrchr(def_cc_name, '\\')) != NULL &&
728
729                   !strcmp(bs_cc, bs_def_cc));
730
731     if (def_cc_name)
732         free(def_cc_name);
733
734     return is_default;
735 }
736
737 /** Given a principal return an existing ccache or create one and return */
738 int
739 KFW_get_ccache(krb5_context alt_context, krb5_principal principal, krb5_ccache * cc)
740 {
741     krb5_context context = NULL;
742     char * pname = NULL;
743     char * ccname = NULL;
744     krb5_error_code code;
745
746     if ( alt_context ) {
747         context = alt_context;
748     } else {
749         code = krb5_init_context(&context);
750         if (code) goto cleanup;
751     }
752
753     if ( principal ) {
754         code = krb5_unparse_name(context, principal, &pname);
755         if (code) goto cleanup;
756
757         if ( !KFW_AFS_find_ccache_for_principal(context,pname,&ccname,TRUE) &&
758              !KFW_AFS_find_ccache_for_principal(context,pname,&ccname,FALSE)) {
759
760             get_default_ccache_name_for_principal(context, principal, &ccname);
761         }
762         code = krb5_cc_resolve(context, ccname, cc);
763     } else {
764         code = krb5_cc_default(context, cc);
765         if (code) goto cleanup;
766     }
767
768   cleanup:
769     if (ccname)
770         free(ccname);
771     if (pname)
772         krb5_free_unparsed_name(context,pname);
773     if (context && (context != alt_context))
774         krb5_free_context(context);
775     return(code);
776 }
777
778 #ifdef USE_MS2MIT
779
780 // Import Microsoft Credentials into a new MIT ccache
781 void
782 KFW_import_windows_lsa(void)
783 {
784     krb5_context context = NULL;
785     krb5_ccache  cc = NULL;
786     krb5_principal princ = NULL;
787     char * pname = NULL;
788     const char *  princ_realm;
789     krb5_error_code code;
790     char cell[128]="", realm[128]="", *def_realm = 0;
791     DWORD dwMsLsaImport = 1;
792
793     code = krb5_init_context(&context);
794     if (code) goto cleanup;
795
796     code = krb5_cc_resolve(context, LSA_CCNAME, &cc);
797     if (code) goto cleanup;
798
799     KFW_AFS_update_princ_ccache_data(context, cc, TRUE);
800
801     code = krb5_cc_get_principal(context, cc, &princ);
802     if ( code ) goto cleanup;
803
804     dwMsLsaImport = KFW_get_default_mslsa_import(context);
805     switch ( dwMsLsaImport ) {
806     case 0: /* do not import */
807         goto cleanup;
808     case 1: /* always import */
809         break;
810     case 2: { /* matching realm */
811         const char *ms_realm;
812
813         ms_realm = krb5_principal_get_realm(context, princ);
814
815         if (code = krb5_get_default_realm(context, &def_realm))
816             goto cleanup;
817
818         if (strcmp(def_realm, ms_realm))
819             goto cleanup;
820         break;
821     }
822     default:
823         break;
824     }
825
826     code = krb5_unparse_name(context,princ,&pname);
827     if ( code ) goto cleanup;
828
829     princ_realm = krb5_principal_get_realm(context, princ);
830     StringCchCopyA(realm, sizeof(realm), princ_realm);
831     StringCchCopyA(cell, sizeof(cell), princ_realm);
832     strlwr(cell);
833
834     code = KFW_AFS_klog(context, cc, "afs", cell, realm,
835                         KFW_get_default_lifetime(context, realm), NULL);
836
837     DebugPrintf("KFW_AFS_klog() returns: %d\n", code);
838
839     if ( code ) goto cleanup;
840
841     KFW_AFS_update_cell_princ_map(context, cell, pname, TRUE);
842
843   cleanup:
844     if (pname)
845         krb5_free_unparsed_name(context,pname);
846     if (princ)
847         krb5_free_principal(context,princ);
848     if (def_realm)
849         krb5_free_default_realm(context, def_realm);
850     if (cc)
851         krb5_cc_close(context,cc);
852     if (context)
853         krb5_free_context(context);
854 }
855 #endif /* USE_MS2MIT */
856
857 static krb5_boolean
858 get_canonical_ccache(krb5_context context, krb5_ccache * pcc)
859 {
860     krb5_error_code code;
861     krb5_ccache cc = *pcc;
862     krb5_principal principal = 0;
863
864     code = krb5_cc_get_principal(context, cc, &principal);
865     if (code)
866         return FALSE;
867
868     if ( !is_default_ccache_for_principal(context, principal, cc)
869          && strcmp(krb5_cc_get_type(context, cc), LSA_CCTYPE) != 0) {
870
871         char * def_cc_name = NULL;
872         krb5_ccache def_cc = 0;
873         krb5_principal def_cc_princ = 0;
874
875         do {
876             get_default_ccache_name_for_principal(context, principal, &def_cc_name);
877
878             code = krb5_cc_resolve(context, def_cc_name, &def_cc);
879             if (code) break;
880
881             code = krb5_cc_get_principal(context, def_cc, &def_cc_princ);
882             if (code || !krb5_principal_compare(context, def_cc_princ, principal)) {
883                 /* def_cc either doesn't exist or is home to an
884                  * imposter. */
885
886                 DebugPrintf("Copying ccache [%s:%s]->[%s:%s]",
887                             krb5_cc_get_type(context, cc), krb5_cc_get_name(context, cc),
888                             krb5_cc_get_type(context, def_cc),
889                             krb5_cc_get_name(context, def_cc));
890
891                 code = krb5_cc_initialize(context, def_cc, principal);
892                 if (code) break;
893
894                 code = krb5_cc_copy_creds(context, cc, def_cc);
895                 if (code) {
896                     KRB5_error(code, "krb5_cc_copy_creds", 0, NULL, NULL);
897                     break;
898                 }
899
900                 code = krb5_cc_close(context, cc);
901
902                 cc = def_cc;
903                 def_cc = 0;
904             }
905         } while (FALSE);
906
907         if (def_cc)
908             krb5_cc_close(context, def_cc);
909
910         if (def_cc_princ)
911             krb5_free_principal(context, def_cc_princ);
912
913         if (def_cc_name)
914             free(def_cc_name);
915     }
916
917     if (principal)
918         krb5_free_principal(context, principal);
919
920     if (code == 0 && cc != 0) {
921         *pcc = cc;
922         return TRUE;
923     }
924
925     *pcc = cc;
926     return FALSE;
927 }
928
929 static krb5_error_code
930 check_and_get_tokens_for_ccache(krb5_context context, krb5_ccache cc)
931 {
932     krb5_error_code code = 0;
933     krb5_error_code cc_code = 0;
934     krb5_cc_cursor  cur;
935     krb5_creds      creds;
936     char * principal_name = NULL;
937
938     {
939         krb5_principal principal = 0;
940         code = krb5_cc_get_principal(context, cc, &principal);
941
942         if (code == 0)
943             code = krb5_unparse_name(context, principal, &principal_name);
944
945         if (principal)
946             krb5_free_principal(context, principal);
947     }
948
949     if (code != 0) {
950         if (principal_name)
951             krb5_free_unparsed_name(context, principal_name);
952         return code;
953     }
954
955     cc_code = krb5_cc_start_seq_get(context, cc, &cur);
956
957     while (!(cc_code = krb5_cc_next_cred(context, cc, &cur, &creds))) {
958
959         const char * sname = krb5_principal_get_comp_string(context, creds.server, 0);
960         const char * cell  = krb5_principal_get_comp_string(context, creds.server, 1);
961         const char * realm = krb5_principal_get_realm(context, creds.server);
962
963         if ( sname && cell && !strcmp("afs",sname) ) {
964
965             struct ktc_principal    aserver;
966             struct ktc_principal    aclient;
967             struct ktc_token        atoken;
968             int active = TRUE;
969
970             DebugPrintf("Found AFS ticket: %s%s%s@%s\n",
971                         sname, (cell ? "/":""), (cell? cell : ""), realm);
972
973             memset(&aserver, '\0', sizeof(aserver));
974             StringCbCopy(aserver.name, sizeof(aserver.name), sname);
975             StringCbCopy(aserver.cell, sizeof(aserver.cell), cell);
976
977             code = ktc_GetToken(&aserver, &atoken, sizeof(atoken), &aclient);
978             if (!code) {
979                 // Found a token in AFS Client Server which matches
980
981                 char pname[128], *p, *q;
982
983                 for ( p=pname, q=aclient.name; *q; p++, q++)
984                     *p = *q;
985
986                 for ( *p++ = '@', q=aclient.cell; *q; p++, q++)
987                     *p = toupper(*q);
988
989                 *p = '\0';
990
991                 DebugPrintf("Found AFS token: %s\n", pname);
992
993                 if (strcmp(pname, principal_name) != 0)
994                     active = FALSE;
995
996                 KFW_AFS_update_cell_princ_map(context, cell, principal_name, active);
997
998             } else {
999                 // Attempt to import it
1000
1001                 KFW_AFS_update_cell_princ_map(context, cell, principal_name, active);
1002
1003                 DebugPrintf("Calling KFW_AFS_klog() to obtain token\n");
1004
1005                 code = KFW_AFS_klog(context, cc, "afs", cell, realm,
1006                                     KFW_get_default_lifetime(context, realm), NULL);
1007
1008                 DebugPrintf("KFW_AFS_klog() returns: %d\n", code);
1009             }
1010
1011         } else {
1012
1013             DebugPrintf("Found ticket: %s%s%s@%s\n", sname,
1014                         (cell? "/":""), (cell? cell:""), realm);
1015         }
1016
1017         krb5_free_cred_contents(context, &creds);
1018     }
1019
1020     if (cc_code == KRB5_CC_END) {
1021         cc_code = krb5_cc_end_seq_get(context, cc, &cur);
1022     }
1023
1024     return code;
1025 }
1026
1027 // If there are existing MIT credentials, copy them to a new
1028 // ccache named after the principal
1029
1030 // Enumerate all existing MIT ccaches and construct entries
1031 // in the principal_ccache table
1032
1033 // Enumerate all existing AFS Tokens and construct entries
1034 // in the cell_principal table
1035 void
1036 KFW_import_ccache_data(void)
1037 {
1038     krb5_context context = NULL;
1039     krb5_ccache  cc;
1040     krb5_error_code code;
1041     krb5_cccol_cursor cccol_cur;
1042     int flags;
1043
1044     if ( IsDebuggerPresent() )
1045         OutputDebugString("KFW_import_ccache_data()\n");
1046
1047     code = krb5_init_context(&context);
1048     if (code) goto cleanup;
1049
1050     code = krb5_cccol_cursor_new(context, &cccol_cur);
1051     if (code) goto cleanup;
1052
1053     while ((code = krb5_cccol_cursor_next(context, cccol_cur, &cc)) == 0 && cc != NULL) {
1054
1055         if (!get_canonical_ccache(context, &cc)) {
1056             if (cc)
1057                 krb5_cc_close(context, cc);
1058             continue;
1059         }
1060
1061         /* Turn off OPENCLOSE mode */
1062         code = krb5_cc_set_flags(context, cc, 0);
1063         if ( code ) goto cleanup;
1064
1065         KFW_AFS_update_princ_ccache_data(context, cc,
1066                                          !strcmp(krb5_cc_get_type(context, cc),
1067                                                  LSA_CCTYPE));
1068
1069         check_and_get_tokens_for_ccache(context, cc);
1070
1071         flags = KRB5_TC_OPENCLOSE;  //turn on OPENCLOSE
1072         code = krb5_cc_set_flags(context, cc, flags);
1073
1074         if (cc) {
1075             krb5_cc_close(context,cc);
1076             cc = 0;
1077         }
1078     }
1079
1080     krb5_cccol_cursor_free(context, &cccol_cur);
1081
1082   cleanup:
1083     if (context)
1084         krb5_free_context(context);
1085 }
1086
1087
1088 int
1089 KFW_AFS_get_cred( char * username,
1090                   char * cell,
1091                   char * password,
1092                   int lifetime,
1093                   char * smbname,
1094                   char ** reasonP )
1095 {
1096     static char reason[1024]="";
1097     krb5_context context = NULL;
1098     krb5_ccache cc = NULL;
1099     char * realm = NULL, * userrealm = NULL;
1100     krb5_principal principal = NULL;
1101     char * pname = NULL;
1102     krb5_error_code code;
1103     char local_cell[CELL_MAXNAMELEN+1];
1104     char **cells = NULL;
1105     int  cell_count=0;
1106     struct afsconf_cell cellconfig;
1107     char * dot;
1108
1109     DebugPrintf("KFW_AFS_get_cred for token %s in cell %s\n", username, cell);
1110
1111     memset(&cellconfig, 0, sizeof(cellconfig));
1112
1113     code = krb5_init_context(&context);
1114     if ( code ) goto cleanup;
1115
1116     code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1117     if ( code ) goto cleanup;
1118
1119     realm = afs_realm_of_cell(context, &cellconfig);  // do not free
1120
1121     userrealm = strchr(username,'@');
1122     if ( userrealm ) {
1123         pname = strdup(username);
1124         if (!KFW_accept_dotted_usernames()) {
1125             userrealm = strchr(pname, '@');
1126             *userrealm = '\0';
1127
1128             /* handle kerberos iv notation */
1129             while ( dot = strchr(pname,'.') ) {
1130                 *dot = '/';
1131             }
1132             *userrealm = '@';
1133         }
1134         userrealm++;
1135     } else {
1136         size_t len = strlen(username) + strlen(realm) + 2;
1137         pname = malloc(len);
1138         if (pname == NULL) {
1139             code = KRB5KRB_ERR_GENERIC;
1140             goto cleanup;
1141         }
1142         StringCbCopy(pname, len, username);
1143
1144         if (!KFW_accept_dotted_usernames()) {
1145             /* handle kerberos iv notation */
1146             while ( dot = strchr(pname,'.') ) {
1147                 *dot = '/';
1148             }
1149         }
1150         StringCbCat( pname, len, "@");
1151         StringCbCat( pname, len, realm);
1152     }
1153     if ( IsDebuggerPresent() ) {
1154         OutputDebugString("Realm of Cell: ");
1155         OutputDebugString(realm);
1156         OutputDebugString("\n");
1157         OutputDebugString("Realm of User: ");
1158         OutputDebugString(userrealm?userrealm:"<NULL>");
1159         OutputDebugString("\n");
1160     }
1161
1162     code = krb5_parse_name(context, pname, &principal);
1163     if ( code ) goto cleanup;
1164
1165     code = KFW_get_ccache(context, principal, &cc);
1166     if ( code ) goto cleanup;
1167
1168     if ( lifetime == 0 )
1169         lifetime = KFW_get_default_lifetime(context, realm);
1170
1171     if ( password && password[0] ) {
1172         code = KFW_kinit( context, cc, HWND_DESKTOP,
1173                           pname,
1174                           password,
1175                           lifetime,
1176 #ifndef USE_LEASH
1177                           0, /* forwardable */
1178                           0, /* not proxiable */
1179                           1, /* renewable */
1180                           1, /* noaddresses */
1181                           0  /* no public ip */
1182 #else
1183                           pLeash_get_default_forwardable(),
1184                           pLeash_get_default_proxiable(),
1185                           pLeash_get_default_renewable() ? pLeash_get_default_renew_till() : 0,
1186                           pLeash_get_default_noaddresses(),
1187                           pLeash_get_default_publicip()
1188 #endif /* USE_LEASH */
1189                           );
1190
1191         if ( IsDebuggerPresent() ) {
1192             char message[256];
1193             StringCbPrintf(message, sizeof(message), "KFW_kinit() returns: %d\n", code);
1194             OutputDebugString(message);
1195         }
1196         if ( code ) goto cleanup;
1197
1198         KFW_AFS_update_princ_ccache_data(context, cc, FALSE);
1199     }
1200
1201     code = KFW_AFS_klog(context, cc, "afs", cell, realm, lifetime, smbname);
1202     if ( IsDebuggerPresent() ) {
1203         char message[256];
1204         StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1205         OutputDebugString(message);
1206     }
1207     if ( code ) goto cleanup;
1208
1209     KFW_AFS_update_cell_princ_map(context, cell, pname, TRUE);
1210
1211     // Attempt to obtain new tokens for other cells supported by the same
1212     // principal
1213     cell_count = KFW_AFS_find_cells_for_princ(context, pname, &cells, TRUE);
1214     if ( cell_count > 1 ) {
1215         while ( cell_count-- ) {
1216             if ( strcmp(cells[cell_count],cell) ) {
1217                 if ( IsDebuggerPresent() ) {
1218                     char message[256];
1219                     StringCbPrintf(message, sizeof(message),
1220                                    "found another cell for the same principal: %s\n", cell);
1221                     OutputDebugString(message);
1222                 }
1223
1224                 if (cellconfig.linkedCell) {
1225                     free(cellconfig.linkedCell);
1226                     cellconfig.linkedCell = NULL;
1227                 }
1228                 code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1229                 if ( code ) continue;
1230
1231                 realm = afs_realm_of_cell(context, &cellconfig);  // do not free
1232                 if ( IsDebuggerPresent() ) {
1233                     OutputDebugString("Realm: ");
1234                     OutputDebugString(realm);
1235                     OutputDebugString("\n");
1236                 }
1237
1238                 code = KFW_AFS_klog(context, cc, "afs", cells[cell_count], realm, lifetime, smbname);
1239                 if ( IsDebuggerPresent() ) {
1240                     char message[256];
1241                     StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1242                     OutputDebugString(message);
1243                 }
1244             }
1245             free(cells[cell_count]);
1246         }
1247         free(cells);
1248     } else if ( cell_count == 1 ) {
1249         free(cells[0]);
1250         free(cells);
1251     }
1252
1253   cleanup:
1254     if ( pname )
1255         free(pname);
1256     if ( cc )
1257         krb5_cc_close(context, cc);
1258     if ( cellconfig.linkedCell )
1259         free(cellconfig.linkedCell);
1260
1261     if ( code && reasonP ) {
1262         const char *msg = krb5_get_error_message(context, code);
1263         StringCbCopyN( reason, sizeof(reason),
1264                        msg, sizeof(reason) - 1);
1265         *reasonP = reason;
1266         krb5_free_error_message(context, msg);
1267     }
1268     return(code);
1269 }
1270
1271 int
1272 KFW_AFS_destroy_tickets_for_cell(char * cell)
1273 {
1274     krb5_context        context = NULL;
1275     krb5_error_code     code;
1276     int count;
1277     char ** principals = NULL;
1278
1279     DebugPrintf("KFW_AFS_destroy_tickets_for_cell: %s\n", cell);
1280
1281     code = krb5_init_context(&context);
1282     if (code) context = 0;
1283
1284     count = KFW_AFS_find_principals_for_cell(context, cell, &principals, FALSE);
1285     if ( count > 0 ) {
1286         krb5_principal      princ = 0;
1287         krb5_ccache                     cc  = 0;
1288
1289         while ( count-- ) {
1290             int cell_count = KFW_AFS_find_cells_for_princ(context, principals[count], NULL, TRUE);
1291             if ( cell_count > 1 ) {
1292                 // TODO - What we really should do here is verify whether or not any of the
1293                 // other cells which use this principal to obtain its credentials actually
1294                 // have valid tokens or not.  If they are currently using these credentials
1295                 // we will skip them.  For the time being we assume that if there is an active
1296                 // map in the table that they are actively being used.
1297                 goto loop_cleanup;
1298             }
1299
1300             code = krb5_parse_name(context, principals[count], &princ);
1301             if (code) goto loop_cleanup;
1302
1303             code = KFW_get_ccache(context, princ, &cc);
1304             if (code) goto loop_cleanup;
1305
1306             code = krb5_cc_destroy(context, cc);
1307             if (!code) cc = 0;
1308
1309           loop_cleanup:
1310             if ( cc ) {
1311                 krb5_cc_close(context, cc);
1312                 cc = 0;
1313             }
1314             if ( princ ) {
1315                 krb5_free_principal(context, princ);
1316                 princ = 0;
1317             }
1318
1319             KFW_AFS_update_cell_princ_map(context, cell, principals[count], FALSE);
1320             free(principals[count]);
1321         }
1322         free(principals);
1323     }
1324     if (context)
1325                 krb5_free_context(context);
1326     return 0;
1327 }
1328
1329 int
1330 KFW_AFS_destroy_tickets_for_principal(char * user)
1331 {
1332     krb5_context        context = NULL;
1333     krb5_error_code     code;
1334     int count;
1335     char ** cells = NULL;
1336     krb5_principal      princ = NULL;
1337     krb5_ccache         cc  = NULL;
1338
1339     DebugPrintf("KFW_AFS_destroy_tickets_for_user: %s\n", user);
1340
1341     code = krb5_init_context(&context);
1342     if (code) return 0;
1343
1344     code = krb5_parse_name(context, user, &princ);
1345     if (code) goto loop_cleanup;
1346
1347     code = KFW_get_ccache(context, princ, &cc);
1348     if (code) goto loop_cleanup;
1349
1350     code = krb5_cc_destroy(context, cc);
1351     if (!code) cc = 0;
1352
1353   loop_cleanup:
1354     if ( cc ) {
1355         krb5_cc_close(context, cc);
1356         cc = 0;
1357     }
1358     if ( princ ) {
1359         krb5_free_principal(context, princ);
1360         princ = 0;
1361     }
1362
1363     count = KFW_AFS_find_cells_for_princ(context, user, &cells, TRUE);
1364     if ( count >= 1 ) {
1365         while ( count-- ) {
1366             KFW_AFS_update_cell_princ_map(context, cells[count], user, FALSE);
1367             free(cells[count]);
1368         }
1369         free(cells);
1370     }
1371
1372     if (context)
1373         krb5_free_context(context);
1374
1375     return 0;
1376 }
1377
1378 int
1379 KFW_AFS_renew_expiring_tokens(void)
1380 {
1381     krb5_error_code     code = 0;
1382     krb5_context        context = NULL;
1383     krb5_ccache         cc = NULL;
1384     krb5_timestamp now;
1385     struct principal_ccache_data * pcc_next = princ_cc_data;
1386     int cell_count;
1387     char ** cells=NULL;
1388     const char * realm = NULL;
1389     char local_cell[CELL_MAXNAMELEN+1]="";
1390     struct afsconf_cell cellconfig;
1391
1392     if ( pcc_next == NULL ) // nothing to do
1393         return 0;
1394
1395     if ( IsDebuggerPresent() ) {
1396         OutputDebugString("KFW_AFS_renew_expiring_tokens\n");
1397     }
1398
1399     memset(&cellconfig, 0, sizeof(cellconfig));
1400
1401     code = krb5_init_context(&context);
1402     if (code) goto cleanup;
1403
1404     code = krb5_timeofday(context, &now);
1405     if (code) goto cleanup;
1406
1407     for ( ; pcc_next ; pcc_next = pcc_next->next ) {
1408         if ( pcc_next->expired )
1409             continue;
1410
1411         if ( now >= (pcc_next->expiration_time) ) {
1412             if ( !pcc_next->from_lsa ) {
1413                 pcc_next->expired = 1;
1414                 continue;
1415             }
1416         }
1417
1418         if ( pcc_next->renew && now >= (pcc_next->expiration_time - cminRENEW * csec1MINUTE) ) {
1419             code = krb5_cc_resolve(context, pcc_next->ccache_name, &cc);
1420             if ( code )
1421                 goto loop_cleanup;
1422             code = KFW_renew(context,cc);
1423 #ifdef USE_MS2MIT
1424             if ( code && pcc_next->from_lsa)
1425                 goto loop_cleanup;
1426 #endif /* USE_MS2MIT */
1427
1428
1429             KFW_AFS_update_princ_ccache_data(context, cc, pcc_next->from_lsa);
1430             if (code) goto loop_cleanup;
1431
1432             // Attempt to obtain new tokens for other cells supported by the same
1433             // principal
1434             cell_count = KFW_AFS_find_cells_for_princ(context, pcc_next->principal, &cells, TRUE);
1435             if ( cell_count > 0 ) {
1436                 while ( cell_count-- ) {
1437                     if ( IsDebuggerPresent() ) {
1438                         OutputDebugString("Cell: ");
1439                         OutputDebugString(cells[cell_count]);
1440                         OutputDebugString("\n");
1441                     }
1442                     if (cellconfig.linkedCell) {
1443                         free(cellconfig.linkedCell);
1444                         cellconfig.linkedCell = NULL;
1445                     }
1446                     code = KFW_AFS_get_cellconfig( cells[cell_count], (void*)&cellconfig, local_cell);
1447                     if ( code ) continue;
1448                     realm = afs_realm_of_cell(context, &cellconfig);  // do not free
1449                     if ( IsDebuggerPresent() ) {
1450                         OutputDebugString("Realm: ");
1451                         OutputDebugString(realm);
1452                         OutputDebugString("\n");
1453                     }
1454                     code = KFW_AFS_klog(context, cc, "afs", cells[cell_count], (char *)realm, 0, NULL);
1455                     if ( IsDebuggerPresent() ) {
1456                         char message[256];
1457                         StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1458                         OutputDebugString(message);
1459                     }
1460                     free(cells[cell_count]);
1461                 }
1462                 free(cells);
1463             }
1464         }
1465
1466       loop_cleanup:
1467         if ( cc ) {
1468             krb5_cc_close(context,cc);
1469             cc = 0;
1470         }
1471     }
1472
1473   cleanup:
1474     if ( cc )
1475         krb5_cc_close(context,cc);
1476     if ( context )
1477         krb5_free_context(context);
1478     if (cellconfig.linkedCell)
1479         free(cellconfig.linkedCell);
1480
1481     return 0;
1482 }
1483
1484
1485 BOOL
1486 KFW_AFS_renew_token_for_cell(char * cell)
1487 {
1488     krb5_error_code     code = 0;
1489     krb5_context        context = NULL;
1490     int count;
1491     char ** principals = NULL;
1492
1493     if ( IsDebuggerPresent() ) {
1494         OutputDebugString("KFW_AFS_renew_token_for_cell:");
1495         OutputDebugString(cell);
1496         OutputDebugString("\n");
1497     }
1498
1499     code = krb5_init_context(&context);
1500     if (code) goto cleanup;
1501
1502     count = KFW_AFS_find_principals_for_cell(context, cell, &principals, TRUE);
1503     if ( count == 0 ) {
1504         // We know we must have a credential somewhere since we are
1505         // trying to renew a token
1506
1507         KFW_import_ccache_data();
1508         count = KFW_AFS_find_principals_for_cell(context, cell, &principals, TRUE);
1509     }
1510     if ( count > 0 ) {
1511         krb5_principal      princ = 0;
1512         krb5_principal      service = 0;
1513 #ifdef COMMENT
1514         krb5_creds          mcreds, creds;
1515 #endif /* COMMENT */
1516         krb5_ccache                     cc  = 0;
1517         const char * realm = NULL;
1518         struct afsconf_cell cellconfig;
1519         char local_cell[CELL_MAXNAMELEN+1];
1520
1521         memset(&cellconfig, 0, sizeof(cellconfig));
1522
1523         while ( count-- ) {
1524             code = krb5_parse_name(context, principals[count], &princ);
1525             if (code) goto loop_cleanup;
1526
1527             code = KFW_get_ccache(context, princ, &cc);
1528             if (code) goto loop_cleanup;
1529
1530             if (cellconfig.linkedCell) {
1531                 free(cellconfig.linkedCell);
1532                 cellconfig.linkedCell = NULL;
1533             }
1534             code = KFW_AFS_get_cellconfig( cell, (void*)&cellconfig, local_cell);
1535             if ( code ) goto loop_cleanup;
1536
1537             realm = afs_realm_of_cell(context, &cellconfig);  // do not free
1538             if ( IsDebuggerPresent() ) {
1539                 OutputDebugString("Realm: ");
1540                 OutputDebugString(realm);
1541                 OutputDebugString("\n");
1542             }
1543
1544 #ifdef COMMENT
1545             /* krb5_cc_remove_cred() is not implemented
1546              * for a single cred
1547              */
1548             code = krb5_build_principal(context, &service, strlen(realm),
1549                                           realm, "afs", cell, NULL);
1550             if (!code) {
1551                 memset(&mcreds, 0, sizeof(krb5_creds));
1552                 mcreds.client = princ;
1553                 mcreds.server = service;
1554
1555                 code = krb5_cc_retrieve_cred(context, cc, 0, &mcreds, &creds);
1556                 if (!code) {
1557                     if ( IsDebuggerPresent() ) {
1558                         char * cname, *sname;
1559                         krb5_unparse_name(context, creds.client, &cname);
1560                         krb5_unparse_name(context, creds.server, &sname);
1561                         OutputDebugString("Removing credential for client \"");
1562                         OutputDebugString(cname);
1563                         OutputDebugString("\" and service \"");
1564                         OutputDebugString(sname);
1565                         OutputDebugString("\"\n");
1566                         krb5_free_unparsed_name(context,cname);
1567                         krb5_free_unparsed_name(context,sname);
1568                     }
1569
1570                     code = krb5_cc_remove_cred(context, cc, 0, &creds);
1571                     krb5_free_principal(context, creds.client);
1572                     krb5_free_principal(context, creds.server);
1573                 }
1574             }
1575 #endif /* COMMENT */
1576
1577             code = KFW_AFS_klog(context, cc, "afs", cell, (char *)realm, 0,NULL);
1578             if ( IsDebuggerPresent() ) {
1579                 char message[256];
1580                 StringCbPrintf(message, sizeof(message), "KFW_AFS_klog() returns: %d\n", code);
1581                 OutputDebugString(message);
1582             }
1583
1584           loop_cleanup:
1585             if (cc) {
1586                 krb5_cc_close(context, cc);
1587                 cc = 0;
1588             }
1589             if (princ) {
1590                 krb5_free_principal(context, princ);
1591                 princ = 0;
1592             }
1593             if (service) {
1594                 krb5_free_principal(context, service);
1595                 princ = 0;
1596             }
1597             if (cellconfig.linkedCell) {
1598                 free(cellconfig.linkedCell);
1599                 cellconfig.linkedCell = NULL;
1600             }
1601
1602             KFW_AFS_update_cell_princ_map(context, cell, principals[count], code ? FALSE : TRUE);
1603             free(principals[count]);
1604         }
1605         free(principals);
1606     } else
1607         code = -1;      // we did not renew the tokens
1608
1609   cleanup:
1610     if (context)
1611         krb5_free_context(context);
1612     return (code ? FALSE : TRUE);
1613
1614 }
1615
1616 int
1617 KFW_AFS_renew_tokens_for_all_cells(void)
1618 {
1619     struct cell_principal_map * next = cell_princ_map;
1620
1621     DebugPrintf("KFW_AFS_renew_tokens_for_all()\n");
1622
1623     if ( !next )
1624         return 0;
1625
1626     for ( ; next ; next = next->next ) {
1627         if ( next->active )
1628             KFW_AFS_renew_token_for_cell(next->cell);
1629     }
1630     return 0;
1631 }
1632
1633 int
1634 KFW_renew(krb5_context alt_context, krb5_ccache alt_cc)
1635 {
1636     krb5_error_code     code = 0;
1637     krb5_context        context = NULL;
1638     krb5_ccache         cc = NULL;
1639     krb5_principal      me = NULL;
1640     krb5_principal      server = NULL;
1641     krb5_creds          my_creds;
1642     const char          *realm = NULL;
1643
1644     memset(&my_creds, 0, sizeof(krb5_creds));
1645
1646     if ( alt_context ) {
1647         context = alt_context;
1648     } else {
1649         code = krb5_init_context(&context);
1650         if (code) goto cleanup;
1651     }
1652
1653     if ( alt_cc ) {
1654         cc = alt_cc;
1655     } else {
1656         code = krb5_cc_default(context, &cc);
1657         if (code) goto cleanup;
1658     }
1659
1660     code = krb5_cc_get_principal(context, cc, &me);
1661     if (code) goto cleanup;
1662
1663     realm = krb5_principal_get_realm(context, me);
1664
1665     code = krb5_make_principal(context, &server, realm,
1666                                KRB5_TGS_NAME, realm, NULL);
1667     if ( code )
1668         goto cleanup;
1669
1670     if ( IsDebuggerPresent() ) {
1671         char * cname, *sname;
1672         krb5_unparse_name(context, me, &cname);
1673         krb5_unparse_name(context, server, &sname);
1674         DebugPrintf("Renewing credential for client \"%s\" and service\"%s\"\n",
1675                     cname, sname);
1676         krb5_free_unparsed_name(context,cname);
1677         krb5_free_unparsed_name(context,sname);
1678     }
1679
1680     my_creds.client = me;
1681     my_creds.server = server;
1682
1683     code = krb5_get_renewed_creds(context, &my_creds, me, cc, NULL);
1684     if (code) {
1685         DebugPrintf("krb5_get_renewed_creds() failed: %d\n", code);
1686         goto cleanup;
1687     }
1688
1689     code = krb5_cc_initialize(context, cc, me);
1690     if (code) {
1691         DebugPrintf("krb5_cc_initialize() failed: %d\n", code);
1692         goto cleanup;
1693     }
1694
1695     code = krb5_cc_store_cred(context, cc, &my_creds);
1696     if (code) {
1697         DebugPrintf("krb5_cc_store_cred() failed: %d\n", code);
1698         goto cleanup;
1699     }
1700
1701   cleanup:
1702     if (my_creds.client == me)
1703         my_creds.client = 0;
1704     if (my_creds.server == server)
1705         my_creds.server = 0;
1706     krb5_free_cred_contents(context, &my_creds);
1707     if (me)
1708         krb5_free_principal(context, me);
1709     if (server)
1710         krb5_free_principal(context, server);
1711     if (cc && (cc != alt_cc))
1712         krb5_cc_close(context, cc);
1713     if (context && (context != alt_context))
1714         krb5_free_context(context);
1715     return(code);
1716 }
1717
1718 int
1719 KFW_kinit( krb5_context alt_context,
1720            krb5_ccache  alt_cc,
1721            HWND hParent,
1722            char *principal_name,
1723            char *password,
1724            krb5_deltat lifetime,
1725            DWORD                       forwardable,
1726            DWORD                       proxiable,
1727            krb5_deltat                 renew_life,
1728            DWORD                       addressless,
1729            DWORD                       publicIP)
1730 {
1731     krb5_error_code             code = 0;
1732     krb5_context                context = NULL;
1733     krb5_ccache                 cc = NULL;
1734     krb5_principal              me = NULL;
1735     char*                       name = NULL;
1736     krb5_creds                  my_creds;
1737     krb5_get_init_creds_opt     *options = NULL;
1738     krb5_addresses              addrs = {0, NULL};
1739     int                         i = 0, addr_count = 0;
1740
1741     memset(&my_creds, 0, sizeof(my_creds));
1742
1743     if (alt_context) {
1744         context = alt_context;
1745     } else {
1746         code = krb5_init_context(&context);
1747         if (code) goto cleanup;
1748     }
1749
1750     if ( alt_cc ) {
1751         cc = alt_cc;
1752     } else {
1753         code = krb5_cc_default(context, &cc);
1754         if (code) goto cleanup;
1755     }
1756
1757     code = krb5_get_init_creds_opt_alloc(context, &options);
1758     if (code) goto cleanup;
1759
1760     code = krb5_parse_name(context, principal_name, &me);
1761     if (code) goto cleanup;
1762
1763     code = krb5_unparse_name(context, me, &name);
1764     if (code) goto cleanup;
1765
1766     if (lifetime == 0)
1767         lifetime = KFW_get_default_lifetime(context,
1768                                             krb5_principal_get_realm(context, me));
1769
1770     lifetime *= 60;
1771
1772     if (renew_life > 0)
1773         renew_life *= 60;
1774
1775     if (lifetime)
1776         krb5_get_init_creds_opt_set_tkt_life(options, lifetime);
1777     krb5_get_init_creds_opt_set_forwardable(options, forwardable ? 1 : 0);
1778     krb5_get_init_creds_opt_set_proxiable(options, proxiable ? 1 : 0);
1779     krb5_get_init_creds_opt_set_renew_life(options, renew_life);
1780     if (addressless) {
1781         krb5_get_init_creds_opt_set_addressless(context, options, TRUE);
1782     } else {
1783         if (publicIP) {
1784             // we are going to add the public IP address specified by the user
1785             // to the list provided by the operating system
1786             struct sockaddr_in     in_addr;
1787             krb5_address    addr;
1788             krb5_addresses  addr_l;
1789
1790             krb5_get_all_client_addrs(context, &addrs);
1791
1792             in_addr.sin_family = AF_INET;
1793             in_addr.sin_port = 0;
1794             in_addr.sin_addr.S_un.S_addr = htonl(publicIP);
1795
1796             code = krb5_sockaddr2address(context, (struct sockaddr *)&in_addr,
1797                                          &addr);
1798
1799             if (code == 0) {
1800                 addr_l.len = 1;
1801                 addr_l.val = &addr;
1802
1803                 code = krb5_append_addresses(context, &addrs, &addr_l);
1804
1805                 krb5_free_address(context, &addr);
1806             }
1807
1808             krb5_get_init_creds_opt_set_address_list(options, &addrs);
1809         }
1810     }
1811
1812     code = krb5_get_init_creds_password(context,
1813                                        &my_creds,
1814                                        me,
1815                                        password, // password
1816                                        KRB5_prompter, // prompter
1817                                        hParent, // prompter data
1818                                        0, // start time
1819                                        0, // service name
1820                                        options);
1821     if (code)
1822         goto cleanup;
1823
1824     code = krb5_cc_initialize(context, cc, me);
1825     if (code)
1826         goto cleanup;
1827
1828     code = krb5_cc_store_cred(context, cc, &my_creds);
1829     if (code)
1830         goto cleanup;
1831
1832  cleanup:
1833     if ( addrs.len > 0 )
1834         krb5_free_addresses(context, &addrs);
1835
1836     if (my_creds.client == me)
1837         my_creds.client = 0;
1838
1839     krb5_free_cred_contents(context, &my_creds);
1840     if (name)
1841         krb5_free_unparsed_name(context, name);
1842     if (me)
1843         krb5_free_principal(context, me);
1844     if (options)
1845         krb5_get_init_creds_opt_free(context, options);
1846     if (cc && (cc != alt_cc))
1847         krb5_cc_close(context, cc);
1848     if (context && (context != alt_context))
1849         krb5_free_context(context);
1850     return(code);
1851 }
1852
1853
1854 int
1855 KFW_kdestroy(krb5_context alt_context, krb5_ccache alt_cc)
1856 {
1857     krb5_context                context = NULL;
1858     krb5_ccache                 cc = NULL;
1859     krb5_error_code             code;
1860
1861     if (alt_context) {
1862         context = alt_context;
1863     } else {
1864         code = krb5_init_context(&context);
1865         if (code) goto cleanup;
1866     }
1867
1868     if ( alt_cc ) {
1869         cc = alt_cc;
1870     } else {
1871         code = krb5_cc_default(context, &cc);
1872         if (code) goto cleanup;
1873     }
1874
1875     code = krb5_cc_destroy(context, cc);
1876     if ( !code ) cc = 0;
1877
1878   cleanup:
1879     if (cc && (cc != alt_cc))
1880         krb5_cc_close(context, cc);
1881     if (context && (context != alt_context))
1882         krb5_free_context(context);
1883
1884     return(code);
1885 }
1886
1887
1888 #ifdef USE_MS2MIT
1889 static BOOL
1890 GetSecurityLogonSessionData(PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1891 {
1892     NTSTATUS Status = 0;
1893     HANDLE  TokenHandle;
1894     TOKEN_STATISTICS Stats;
1895     DWORD   ReqLen;
1896     BOOL    Success;
1897
1898     if (!ppSessionData)
1899         return FALSE;
1900     *ppSessionData = NULL;
1901
1902     Success = OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1903     if ( !Success )
1904         return FALSE;
1905
1906     Success = GetTokenInformation( TokenHandle, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1907     CloseHandle( TokenHandle );
1908     if ( !Success )
1909         return FALSE;
1910
1911     Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1912     if ( FAILED(Status) || !ppSessionData )
1913         return FALSE;
1914
1915     return TRUE;
1916 }
1917
1918 //
1919 // MSLSA_IsKerberosLogon() does not validate whether or not there are valid tickets in the
1920 // cache.  It validates whether or not it is reasonable to assume that if we
1921 // attempted to retrieve valid tickets we could do so.  Microsoft does not
1922 // automatically renew expired tickets.  Therefore, the cache could contain
1923 // expired or invalid tickets.  Microsoft also caches the user's password
1924 // and will use it to retrieve new TGTs if the cache is empty and tickets
1925 // are requested.
1926
1927 static BOOL
1928 MSLSA_IsKerberosLogon(VOID)
1929 {
1930     PSECURITY_LOGON_SESSION_DATA pSessionData = NULL;
1931     BOOL    Success = FALSE;
1932
1933     if ( GetSecurityLogonSessionData(&pSessionData) ) {
1934         if ( pSessionData->AuthenticationPackage.Buffer ) {
1935             WCHAR buffer[256];
1936             WCHAR *usBuffer;
1937             int usLength;
1938
1939             Success = FALSE;
1940             usBuffer = (pSessionData->AuthenticationPackage).Buffer;
1941             usLength = (pSessionData->AuthenticationPackage).Length;
1942             if (usLength < 256)
1943             {
1944                 StringCbCopyNW( buffer, sizeof(buffer)/sizeof(WCHAR),
1945                                 usBuffer, usLength);
1946                 if ( !lstrcmpW(L"Kerberos",buffer) )
1947                     Success = TRUE;
1948             }
1949         }
1950         LsaFreeReturnBuffer(pSessionData);
1951     }
1952     return Success;
1953 }
1954 #endif /* USE_MS2MIT */
1955
1956 static BOOL CALLBACK
1957 MultiInputDialogProc( HWND hDialog, UINT message, WPARAM wParam, LPARAM lParam)
1958 {
1959     int i;
1960
1961     switch ( message ) {
1962     case WM_INITDIALOG:
1963         if ( GetDlgCtrlID((HWND) wParam) != ID_MID_TEXT )
1964         {
1965             SetFocus(GetDlgItem( hDialog, ID_MID_TEXT));
1966             return FALSE;
1967         }
1968                 for ( i=0; i < mid_cnt ; i++ ) {
1969                         if (mid_tb[i].echo == 0)
1970                                 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, 32, 0);
1971                     else if (mid_tb[i].echo == 2)
1972                                 SendDlgItemMessage(hDialog, ID_MID_TEXT+i, EM_SETPASSWORDCHAR, '*', 0);
1973                 }
1974         return TRUE;
1975
1976     case WM_COMMAND:
1977         switch ( LOWORD(wParam) ) {
1978         case IDOK:
1979             for ( i=0; i < mid_cnt ; i++ ) {
1980                 if ( !GetDlgItemText(hDialog, ID_MID_TEXT+i, mid_tb[i].buf, mid_tb[i].len) )
1981                     *mid_tb[i].buf = '\0';
1982             }
1983             /* fallthrough */
1984         case IDCANCEL:
1985             EndDialog(hDialog, LOWORD(wParam));
1986             return TRUE;
1987         }
1988     }
1989     return FALSE;
1990 }
1991
1992 static LPWORD
1993 lpwAlign( LPWORD lpIn )
1994 {
1995     ULONG_PTR ul;
1996
1997     ul = (ULONG_PTR) lpIn;
1998     ul += 3;
1999     ul >>=2;
2000     ul <<=2;
2001     return (LPWORD) ul;;
2002 }
2003
2004 /*
2005  * dialog widths are measured in 1/4 character widths
2006  * dialog height are measured in 1/8 character heights
2007  */
2008
2009 static LRESULT
2010 MultiInputDialog( HINSTANCE hinst, HWND hwndOwner,
2011                   char * ptext[], int numlines, int width,
2012                   int tb_cnt, struct textField * tb)
2013 {
2014     HGLOBAL hgbl;
2015     LPDLGTEMPLATE lpdt;
2016     LPDLGITEMTEMPLATE lpdit;
2017     LPWORD lpw;
2018     LPWSTR lpwsz;
2019     LRESULT ret;
2020     int nchar, i, pwid;
2021
2022     hgbl = GlobalAlloc(GMEM_ZEROINIT, 4096);
2023     if (!hgbl)
2024         return -1;
2025
2026     mid_cnt = tb_cnt;
2027     mid_tb = tb;
2028
2029     lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
2030
2031     // Define a dialog box.
2032
2033     lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
2034                    | DS_MODALFRAME | WS_CAPTION | DS_CENTER
2035                    | DS_SETFOREGROUND | DS_3DLOOK
2036                    | DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE;
2037     lpdt->cdit = numlines + (2 * tb_cnt) + 2;  // number of controls
2038     lpdt->x  = 10;
2039     lpdt->y  = 10;
2040     lpdt->cx = 20 + width * 4;
2041     lpdt->cy = 20 + (numlines + tb_cnt + 4) * 14;
2042
2043     lpw = (LPWORD) (lpdt + 1);
2044     *lpw++ = 0;   // no menu
2045     *lpw++ = 0;   // predefined dialog box class (by default)
2046
2047     lpwsz = (LPWSTR) lpw;
2048     nchar = MultiByteToWideChar (CP_ACP, 0, "", -1, lpwsz, 128);
2049     lpw   += nchar;
2050     *lpw++ = 8;                        // font size (points)
2051     lpwsz = (LPWSTR) lpw;
2052     nchar = MultiByteToWideChar (CP_ACP, 0, "MS Shell Dlg",
2053                                     -1, lpwsz, 128);
2054     lpw   += nchar;
2055
2056     //-----------------------
2057     // Define an OK button.
2058     //-----------------------
2059     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2060     lpdit = (LPDLGITEMTEMPLATE) lpw;
2061     lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON | WS_TABSTOP | WS_BORDER;
2062     lpdit->dwExtendedStyle = 0;
2063     lpdit->x  = (lpdt->cx - 14)/4 - 20;
2064     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
2065     lpdit->cx = 40;
2066     lpdit->cy = 14;
2067     lpdit->id = IDOK;  // OK button identifier
2068
2069     lpw = (LPWORD) (lpdit + 1);
2070     *lpw++ = 0xFFFF;
2071     *lpw++ = 0x0080;    // button class
2072
2073     lpwsz = (LPWSTR) lpw;
2074     nchar = MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
2075     lpw   += nchar;
2076     *lpw++ = 0;           // no creation data
2077
2078     //-----------------------
2079     // Define an Cancel button.
2080     //-----------------------
2081     lpw = lpwAlign (lpw); // align DLGITEMTEMPLATE on DWORD boundary
2082     lpdit = (LPDLGITEMTEMPLATE) lpw;
2083     lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_TABSTOP | WS_BORDER;
2084     lpdit->dwExtendedStyle = 0;
2085     lpdit->x  = (lpdt->cx - 14)*3/4 - 20;
2086     lpdit->y  = 10 + (numlines + tb_cnt + 2) * 14;
2087     lpdit->cx = 40;
2088     lpdit->cy = 14;
2089     lpdit->id = IDCANCEL;  // CANCEL button identifier
2090
2091     lpw = (LPWORD) (lpdit + 1);
2092     *lpw++ = 0xFFFF;
2093     *lpw++ = 0x0080;    // button class
2094
2095     lpwsz = (LPWSTR) lpw;
2096     nchar = MultiByteToWideChar (CP_ACP, 0, "Cancel", -1, lpwsz, 50);
2097     lpw   += nchar;
2098     *lpw++ = 0;           // no creation data
2099
2100     /* Add controls for preface data */
2101     for ( i=0; i<numlines; i++) {
2102         /*-----------------------
2103          * Define a static text control.
2104          *-----------------------*/
2105         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2106         lpdit = (LPDLGITEMTEMPLATE) lpw;
2107         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2108         lpdit->dwExtendedStyle = 0;
2109         lpdit->x  = 10;
2110         lpdit->y  = 10 + i * 14;
2111         lpdit->cx = (short)strlen(ptext[i]) * 4 + 10;
2112         lpdit->cy = 14;
2113         lpdit->id = ID_TEXT + i;  // text identifier
2114
2115         lpw = (LPWORD) (lpdit + 1);
2116         *lpw++ = 0xFFFF;
2117         *lpw++ = 0x0082;                         // static class
2118
2119         lpwsz = (LPWSTR) lpw;
2120         nchar = MultiByteToWideChar (CP_ACP, 0, ptext[i],
2121                                          -1, lpwsz, 2*width);
2122         lpw   += nchar;
2123         *lpw++ = 0;           // no creation data
2124     }
2125
2126     for ( i=0, pwid = 0; i<tb_cnt; i++) {
2127         int len = (int)strlen(tb[i].label);
2128         if ( pwid < len )
2129             pwid = len;
2130     }
2131
2132     for ( i=0; i<tb_cnt; i++) {
2133         /* Prompt */
2134         /*-----------------------
2135          * Define a static text control.
2136          *-----------------------*/
2137         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2138         lpdit = (LPDLGITEMTEMPLATE) lpw;
2139         lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
2140         lpdit->dwExtendedStyle = 0;
2141         lpdit->x  = 10;
2142         lpdit->y  = 10 + (numlines + i + 1) * 14;
2143         lpdit->cx = pwid * 4;
2144         lpdit->cy = 14;
2145         lpdit->id = ID_TEXT + numlines + i;  // text identifier
2146
2147         lpw = (LPWORD) (lpdit + 1);
2148         *lpw++ = 0xFFFF;
2149         *lpw++ = 0x0082;                         // static class
2150
2151         lpwsz = (LPWSTR) lpw;
2152         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].label ? tb[i].label : "",
2153                                      -1, lpwsz, 128);
2154         lpw   += nchar;
2155         *lpw++ = 0;           // no creation data
2156
2157         /*-----------------------
2158          * Define an edit control.
2159          *-----------------------*/
2160         lpw = lpwAlign (lpw); /* align DLGITEMTEMPLATE on DWORD boundary */
2161         lpdit = (LPDLGITEMTEMPLATE) lpw;
2162         lpdit->style = WS_CHILD | WS_VISIBLE | ES_LEFT | WS_TABSTOP | WS_BORDER | (tb[i].echo == 1 ? 0L : ES_PASSWORD);
2163         lpdit->dwExtendedStyle = 0;
2164         lpdit->x  = 10 + (pwid + 1) * 4;
2165         lpdit->y  = 10 + (numlines + i + 1) * 14;
2166         lpdit->cx = (width - (pwid + 1)) * 4;
2167         lpdit->cy = 14;
2168         lpdit->id = ID_MID_TEXT + i;             // identifier
2169
2170         lpw = (LPWORD) (lpdit + 1);
2171         *lpw++ = 0xFFFF;
2172         *lpw++ = 0x0081;                         // edit class
2173
2174         lpwsz = (LPWSTR) lpw;
2175         nchar = MultiByteToWideChar (CP_ACP, 0, tb[i].def ? tb[i].def : "",
2176                                      -1, lpwsz, 128);
2177         lpw   += nchar;
2178         *lpw++ = 0;           // no creation data
2179     }
2180
2181     GlobalUnlock(hgbl);
2182     ret = DialogBoxIndirect(hinst, (LPDLGTEMPLATE) hgbl,
2183                             hwndOwner, (DLGPROC) MultiInputDialogProc);
2184     GlobalFree(hgbl);
2185
2186     switch ( ret ) {
2187     case 0:     /* Timeout */
2188         return -1;
2189     case IDOK:
2190         return 1;
2191     case IDCANCEL:
2192         return 0;
2193     default: {
2194         char buf[256];
2195         StringCbPrintf(buf, sizeof(buf), "DialogBoxIndirect() failed: %d", GetLastError());
2196         MessageBox(hwndOwner,
2197                     buf,
2198                     "GetLastError()",
2199                     MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
2200         return -1;
2201     }
2202     }
2203 }
2204
2205 static int
2206 multi_field_dialog(HWND hParent, char * preface, int n, struct textField tb[])
2207 {
2208     HINSTANCE hInst = 0;
2209     size_t maxwidth = 0;
2210     int numlines = 0;
2211     size_t len;
2212     char * plines[16], *p = preface ? preface : "";
2213     int i;
2214
2215     for ( i=0; i<16; i++ )
2216         plines[i] = NULL;
2217
2218     while (*p && numlines < 16) {
2219         plines[numlines++] = p;
2220         for ( ;*p && *p != '\r' && *p != '\n'; p++ );
2221         if ( *p == '\r' && *(p+1) == '\n' ) {
2222             *p++ = '\0';
2223             p++;
2224         } else if ( *p == '\n' ) {
2225             *p++ = '\0';
2226         }
2227         if ( strlen(plines[numlines-1]) > maxwidth )
2228             maxwidth = strlen(plines[numlines-1]);
2229     }
2230
2231     for ( i=0;i<n;i++ ) {
2232         len = (int)strlen(tb[i].label) + 1 + (tb[i].len > 40 ? 40 : tb[i].len);
2233         if ( maxwidth < len )
2234             maxwidth = len;
2235     }
2236
2237     return(MultiInputDialog(hInst, hParent, plines, numlines, maxwidth, n, tb)?1:0);
2238 }
2239
2240 static krb5_error_code KRB5_CALLCONV
2241 KRB5_prompter( krb5_context context,
2242                void *data,
2243                const char *name,
2244                const char *banner,
2245                int num_prompts,
2246                krb5_prompt prompts[])
2247 {
2248     krb5_error_code     errcode = 0;
2249     int                 i;
2250     struct textField * tb = NULL;
2251     int    len = 0, blen=0, nlen=0;
2252         HWND hParent = (HWND)data;
2253
2254     if (name)
2255         nlen = (int)strlen(name)+2;
2256
2257     if (banner)
2258         blen = (int)strlen(banner)+2;
2259
2260     tb = (struct textField *) malloc(sizeof(struct textField) * num_prompts);
2261     if ( tb != NULL ) {
2262         int ok;
2263         memset(tb,0,sizeof(struct textField) * num_prompts);
2264         for ( i=0; i < num_prompts; i++ ) {
2265             tb[i].buf = prompts[i].reply->data;
2266             tb[i].len = prompts[i].reply->length;
2267             tb[i].label = prompts[i].prompt;
2268             tb[i].def = NULL;
2269             tb[i].echo = (prompts[i].hidden ? 2 : 1);
2270         }
2271
2272         ok = multi_field_dialog(hParent,(char *)banner,num_prompts,tb);
2273         if ( ok ) {
2274             for ( i=0; i < num_prompts; i++ )
2275                 prompts[i].reply->length = (unsigned int)strlen(prompts[i].reply->data);
2276         } else
2277             errcode = -2;
2278     }
2279
2280     if ( tb )
2281         free(tb);
2282     if (errcode) {
2283         for (i = 0; i < num_prompts; i++) {
2284             memset(prompts[i].reply->data, 0, prompts[i].reply->length);
2285         }
2286     }
2287     return errcode;
2288 }
2289
2290 BOOL
2291 KFW_AFS_wait_for_service_start(void)
2292 {
2293     char    HostName[64];
2294     DWORD   CurrentState;
2295
2296     CurrentState = SERVICE_START_PENDING;
2297     memset(HostName, '\0', sizeof(HostName));
2298     gethostname(HostName, sizeof(HostName));
2299
2300     while (CurrentState != SERVICE_RUNNING || CurrentState != SERVICE_STOPPED)
2301     {
2302         if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2303             return(0);
2304         if ( IsDebuggerPresent() ) {
2305             switch ( CurrentState ) {
2306             case SERVICE_STOPPED:
2307                 OutputDebugString("SERVICE_STOPPED\n");
2308                 break;
2309             case SERVICE_START_PENDING:
2310                 OutputDebugString("SERVICE_START_PENDING\n");
2311                 break;
2312             case SERVICE_STOP_PENDING:
2313                 OutputDebugString("SERVICE_STOP_PENDING\n");
2314                 break;
2315             case SERVICE_RUNNING:
2316                 OutputDebugString("SERVICE_RUNNING\n");
2317                 break;
2318             case SERVICE_CONTINUE_PENDING:
2319                 OutputDebugString("SERVICE_CONTINUE_PENDING\n");
2320                 break;
2321             case SERVICE_PAUSE_PENDING:
2322                 OutputDebugString("SERVICE_PAUSE_PENDING\n");
2323                 break;
2324             case SERVICE_PAUSED:
2325                 OutputDebugString("SERVICE_PAUSED\n");
2326                 break;
2327             default:
2328                 OutputDebugString("UNKNOWN Service State\n");
2329             }
2330         }
2331         if (CurrentState == SERVICE_STOPPED)
2332             return(0);
2333         if (CurrentState == SERVICE_RUNNING)
2334             return(1);
2335         Sleep(500);
2336     }
2337     return(0);
2338 }
2339
2340
2341 int
2342 KFW_AFS_unlog(void)
2343 {
2344     long        rc;
2345     char    HostName[64];
2346     DWORD   CurrentState;
2347
2348     CurrentState = 0;
2349     memset(HostName, '\0', sizeof(HostName));
2350     gethostname(HostName, sizeof(HostName));
2351     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR)
2352         return(0);
2353     if (CurrentState != SERVICE_RUNNING)
2354         return(0);
2355
2356     rc = ktc_ForgetAllTokens();
2357
2358     return(0);
2359 }
2360
2361
2362 #define ALLOW_REGISTER 1
2363 static int
2364 ViceIDToUsername(char *username,
2365                  char *realm_of_user,
2366                  char *realm_of_cell,
2367                  char * cell_to_use,
2368                  struct ktc_principal *aclient,
2369                  struct ktc_principal *aserver,
2370                  struct ktc_token *atoken)
2371 {
2372     static char lastcell[CELL_MAXNAMELEN+1] = { 0 };
2373     static char confdir[512] = { 0 };
2374 #ifdef AFS_ID_TO_NAME
2375     char username_copy[BUFSIZ];
2376 #endif /* AFS_ID_TO_NAME */
2377     long viceId = ANONYMOUSID;          /* AFS uid of user */
2378     int  status = 0;
2379 #ifdef ALLOW_REGISTER
2380     afs_int32 id;
2381 #endif /* ALLOW_REGISTER */
2382
2383     if (confdir[0] == '\0')
2384         cm_GetConfigDir(confdir, sizeof(confdir));
2385
2386     StringCbCopyN( lastcell, sizeof(lastcell),
2387                    aserver->cell, sizeof(lastcell) - 1);
2388
2389     if (!pr_Initialize (0, confdir, aserver->cell)) {
2390         char sname[PR_MAXNAMELEN];
2391         StringCbCopyN( sname, sizeof(sname),
2392                        username, sizeof(sname) - 1);
2393         status = pr_SNameToId (sname, &viceId);
2394         pr_End();
2395     }
2396
2397     /*
2398      * This is a crock, but it is Transarc's crock, so
2399      * we have to play along in order to get the
2400      * functionality.  The way the afs id is stored is
2401      * as a string in the username field of the token.
2402      * Contrary to what you may think by looking at
2403      * the code for tokens, this hack (AFS ID %d) will
2404      * not work if you change %d to something else.
2405      */
2406
2407     /*
2408      * This code is taken from cklog -- it lets people
2409      * automatically register with the ptserver in foreign cells
2410      */
2411
2412 #ifdef ALLOW_REGISTER
2413     if (status == 0) {
2414         if (viceId != ANONYMOUSID) {
2415 #else /* ALLOW_REGISTER */
2416             if ((status == 0) && (viceId != ANONYMOUSID))
2417 #endif /* ALLOW_REGISTER */
2418             {
2419 #ifdef AFS_ID_TO_NAME
2420                 StringCbCopyN( username_copy, sizeof(username_copy),
2421                                username, sizeof(username_copy) - 1);
2422                 snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2423 #endif /* AFS_ID_TO_NAME */
2424             }
2425 #ifdef ALLOW_REGISTER
2426         } else if (strcmp(realm_of_user, realm_of_cell) != 0) {
2427             id = 0;
2428             StringCbCopyN( aclient->name, sizeof(aclient->name),
2429                            username, sizeof(aclient->name) - 1);
2430             aclient->instance[0] = '\0';
2431             StringCbCopyN( aclient->cell, sizeof(aclient->cell),
2432                            realm_of_user, sizeof(aclient->cell) - 1);
2433             if (status = ktc_SetToken(aserver, atoken, aclient, 0))
2434                 return status;
2435             if (status = pr_Initialize(1L, confdir, aserver->cell))
2436                 return status;
2437             status = pr_CreateUser(username, &id);
2438             pr_End();
2439             if (status)
2440                 return status;
2441 #ifdef AFS_ID_TO_NAME
2442             StringCbCopyN( username_copy, sizeof(username_copy),
2443                            username, sizeof(username_copy) - 1);
2444             snprintf (username, BUFSIZ, "%s (AFS ID %d)", username_copy, (int) viceId);
2445 #endif /* AFS_ID_TO_NAME */
2446         }
2447     }
2448 #endif /* ALLOW_REGISTER */
2449     return status;
2450 }
2451
2452
2453 static void
2454 copy_realm_of_ticket(krb5_context context, char * dest, size_t destlen, krb5_creds *v5cred) {
2455     Ticket ticket;
2456     size_t len;
2457     int ret;
2458
2459     ret = decode_Ticket(v5cred->ticket.data, v5cred->ticket.length,
2460                         &ticket, &len);
2461     if (ret == 0) {
2462         StringCbCopy(dest, destlen, ticket.realm);
2463
2464         free_Ticket(&ticket);
2465     }
2466 }
2467
2468 int
2469 KFW_AFS_klog(
2470     krb5_context alt_context,
2471     krb5_ccache  alt_cc,
2472     char *service,
2473     char *cell,
2474     char *realm,
2475     int  lifetime,      /* unused parameter */
2476     char *smbname
2477     )
2478 {
2479     long        rc = 0;
2480     struct ktc_principal        aserver;
2481     struct ktc_principal        aclient;
2482     char        realm_of_user[REALM_SZ]; /* Kerberos realm of user */
2483     char        realm_of_cell[REALM_SZ]; /* Kerberos realm of cell */
2484     char        local_cell[CELL_MAXNAMELEN+1];
2485     char        Dmycell[CELL_MAXNAMELEN+1];
2486     struct ktc_token    atoken;
2487     struct ktc_token    btoken;
2488     struct afsconf_cell ak_cellconfig; /* General information about the cell */
2489     char        RealmName[128];
2490     char        CellName[128];
2491     char        ServiceName[128];
2492     DWORD       CurrentState;
2493     char        HostName[64];
2494     krb5_context  context = NULL;
2495     krb5_ccache   cc = NULL;
2496     krb5_creds increds;
2497     krb5_creds * k5creds = NULL;
2498     krb5_error_code code;
2499     krb5_principal client_principal = NULL;
2500     krb5_data * k5data = NULL;
2501     unsigned int retry = 0;
2502
2503     CurrentState = 0;
2504     memset(HostName, '\0', sizeof(HostName));
2505     gethostname(HostName, sizeof(HostName));
2506     if (GetServiceStatus(HostName, TRANSARCAFSDAEMON, &CurrentState) != NOERROR) {
2507         if ( IsDebuggerPresent() )
2508             OutputDebugString("Unable to retrieve AFSD Service Status\n");
2509         return(-1);
2510     }
2511     if (CurrentState != SERVICE_RUNNING) {
2512         if ( IsDebuggerPresent() )
2513             OutputDebugString("AFSD Service NOT RUNNING\n");
2514         return(-2);
2515     }
2516
2517     memset(&ak_cellconfig, 0, sizeof(ak_cellconfig));
2518     memset(RealmName, '\0', sizeof(RealmName));
2519     memset(CellName, '\0', sizeof(CellName));
2520     memset(ServiceName, '\0', sizeof(ServiceName));
2521     memset(realm_of_user, '\0', sizeof(realm_of_user));
2522     memset(realm_of_cell, '\0', sizeof(realm_of_cell));
2523     if (cell && cell[0])
2524         StringCbCopyN( Dmycell, sizeof(Dmycell),
2525                        cell, sizeof(Dmycell) - 1);
2526     else
2527         memset(Dmycell, '\0', sizeof(Dmycell));
2528
2529     // NULL or empty cell returns information on local cell
2530     if (rc = KFW_AFS_get_cellconfig(Dmycell, &ak_cellconfig, local_cell))
2531     {
2532         // KFW_AFS_error(rc, "get_cellconfig()");
2533         return(rc);
2534     }
2535
2536     if ( alt_context ) {
2537         context = alt_context;
2538     } else {
2539         code = krb5_init_context(&context);
2540         if (code) goto cleanup;
2541     }
2542
2543     if ( alt_cc ) {
2544         cc = alt_cc;
2545     } else {
2546         code = krb5_cc_default(context, &cc);
2547         if (code)
2548             goto cleanup;
2549     }
2550
2551     memset(&increds, 0, sizeof(increds));
2552
2553     code = krb5_cc_get_principal(context, cc, &client_principal);
2554     if (code) {
2555         if ( code == KRB5_CC_NOTFOUND && IsDebuggerPresent() )
2556         {
2557             OutputDebugString("Principal Not Found for ccache\n");
2558         }
2559         goto cleanup;
2560     }
2561
2562     if (!KFW_accept_dotted_usernames()) {
2563         const char * comp;
2564         /* look for client principals which cannot be distinguished
2565          * from Kerberos 4 multi-component principal names
2566          */
2567         comp = krb5_principal_get_comp_string(context,client_principal,0);
2568         if (strchr(comp, '.') != NULL) {
2569             OutputDebugString("Illegal Principal name contains dot in first component\n");
2570             rc = KRB5KRB_ERR_GENERIC;
2571             goto cleanup;
2572         }
2573     }
2574
2575     StringCbCopy(realm_of_user, sizeof(realm_of_user),
2576                  krb5_principal_get_realm(context, client_principal));
2577
2578     StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
2579                    afs_realm_of_cell(context, &ak_cellconfig),
2580                    sizeof(realm_of_cell) - 1);
2581
2582     if (strlen(service) == 0)
2583         StringCbCopy( ServiceName, sizeof(ServiceName), "afs");
2584     else
2585         StringCbCopyN( ServiceName, sizeof(ServiceName),
2586                        service, sizeof(ServiceName) - 1);
2587
2588     if (strlen(cell) == 0)
2589         StringCbCopyN( CellName, sizeof(CellName),
2590                        local_cell, sizeof(CellName) - 1);
2591     else
2592         StringCbCopyN( CellName, sizeof(CellName),
2593                        cell, sizeof(CellName) - 1);
2594
2595     /* This is for Kerberos v4 only */
2596     if (strlen(realm) == 0)
2597         StringCbCopyN( RealmName, sizeof(RealmName),
2598                        realm_of_cell, sizeof(RealmName) - 1);
2599     else
2600         StringCbCopyN( RealmName, sizeof(RealmName),
2601                        realm, sizeof(RealmName) - 1);
2602
2603     code = KRB5KRB_ERR_GENERIC;
2604
2605     increds.client = client_principal;
2606     increds.times.endtime = 0;
2607     /* Ask for DES since that is what V4 understands */
2608     increds.session.keytype = ENCTYPE_DES_CBC_CRC;
2609
2610     /* ALWAYS first try service/cell@CLIENT_REALM */
2611     if (code = krb5_build_principal(context, &increds.server,
2612                                     (int)strlen(realm_of_user),
2613                                     realm_of_user,
2614                                     ServiceName,
2615                                     CellName,
2616                                     0))
2617     {
2618         goto cleanup;
2619     }
2620
2621     if ( IsDebuggerPresent() ) {
2622         char * cname, *sname;
2623         krb5_unparse_name(context, increds.client, &cname);
2624         krb5_unparse_name(context, increds.server, &sname);
2625         OutputDebugString("Getting tickets for \"");
2626         OutputDebugString(cname);
2627         OutputDebugString("\" and service \"");
2628         OutputDebugString(sname);
2629         OutputDebugString("\"\n");
2630         krb5_free_unparsed_name(context,cname);
2631         krb5_free_unparsed_name(context,sname);
2632     }
2633
2634     code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2635     if (code == 0) {
2636         /*
2637          * The client's realm is a local realm for the cell.
2638          * Save it so that later the pts registration will not
2639          * be performed.
2640          */
2641         StringCbCopyN(realm_of_cell, sizeof(realm_of_cell),
2642                       realm_of_user, sizeof(realm_of_cell) - 1);
2643     }
2644
2645     if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2646         code == KRB5_ERR_HOST_REALM_UNKNOWN ||
2647         code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2648         code == KRB5KRB_AP_ERR_MSG_TYPE) {
2649         /*
2650          * If there was a specific realm we are supposed to try
2651          * then use it
2652          */
2653         if (strlen(realm) != 0) {
2654             /* service/cell@REALM */
2655             increds.server = 0;
2656             code = krb5_build_principal(context, &increds.server,
2657                                         (int)strlen(realm),
2658                                         realm,
2659                                         ServiceName,
2660                                         0);
2661
2662             if ( IsDebuggerPresent() ) {
2663                 char * cname, *sname;
2664                 krb5_unparse_name(context, increds.client, &cname);
2665                 krb5_unparse_name(context, increds.server, &sname);
2666                 OutputDebugString("Getting tickets for \"");
2667                 OutputDebugString(cname);
2668                 OutputDebugString("\" and service \"");
2669                 OutputDebugString(sname);
2670                 OutputDebugString("\"\n");
2671                 krb5_free_unparsed_name(context,cname);
2672                 krb5_free_unparsed_name(context,sname);
2673             }
2674
2675             if (!code)
2676                 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2677
2678             if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2679                  code == KRB5_ERR_HOST_REALM_UNKNOWN ||
2680                  code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2681                  code == KRB5KRB_AP_ERR_MSG_TYPE) {
2682                 /* Or service@REALM */
2683                 krb5_free_principal(context,increds.server);
2684                 increds.server = 0;
2685                 code = krb5_build_principal(context, &increds.server,
2686                                             (int)strlen(realm),
2687                                             realm,
2688                                             ServiceName,
2689                                             0);
2690
2691                 if ( IsDebuggerPresent() ) {
2692                     char * cname, *sname;
2693                     krb5_unparse_name(context, increds.client, &cname);
2694                     krb5_unparse_name(context, increds.server, &sname);
2695                     DebugPrintf("Getting tickets for \"%s\" and service \"%s\"\n", cname, sname);
2696                     krb5_free_unparsed_name(context,cname);
2697                     krb5_free_unparsed_name(context,sname);
2698                 }
2699
2700                 if (!code)
2701                     code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2702             }
2703
2704             if (code == 0) {
2705                 /* we have a local realm for the cell */
2706                 StringCbCopyN( realm_of_cell, sizeof(realm_of_cell),
2707                                realm, sizeof(realm_of_cell) - 1);
2708             }
2709         } else {
2710             if (strcmp(realm_of_user, realm_of_cell)) {
2711                 /* Then service/cell@CELL_REALM */
2712                 krb5_free_principal(context,increds.server);
2713                 increds.server = 0;
2714                 code = krb5_build_principal(context, &increds.server,
2715                                             (int)strlen(realm_of_cell),
2716                                             realm_of_cell,
2717                                             ServiceName,
2718                                             CellName,
2719                                              0);
2720                 if ( IsDebuggerPresent()) {
2721                     char * cname, *sname;
2722                     krb5_unparse_name(context, increds.client, &cname);
2723                     krb5_unparse_name(context, increds.server, &sname);
2724                     OutputDebugString("krb5_get_credentials() returned Service Principal Unknown\n");
2725                     OutputDebugString("Trying again: getting tickets for \"");
2726                     OutputDebugString(cname);
2727                     OutputDebugString("\" and service \"");
2728                     OutputDebugString(sname);
2729                     OutputDebugString("\"\n");
2730                     krb5_free_unparsed_name(context,cname);
2731                     krb5_free_unparsed_name(context,sname);
2732                 }
2733
2734                 if (!code)
2735                     code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2736
2737                 if (!code && !strlen(realm_of_cell))
2738                     copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
2739             }
2740         }
2741
2742         if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN ||
2743              code == KRB5_ERR_HOST_REALM_UNKNOWN ||
2744              code == KRB5KRB_ERR_GENERIC /* heimdal */ ||
2745              code == KRB5KRB_AP_ERR_MSG_TYPE) {
2746             /* Finally service@CELL_REALM */
2747             krb5_free_principal(context,increds.server);
2748             increds.server = 0;
2749             code = krb5_build_principal(context, &increds.server,
2750                                         (int)strlen(realm_of_cell),
2751                                         realm_of_cell,
2752                                         ServiceName,
2753                                         0);
2754
2755             if ( IsDebuggerPresent() ) {
2756                 char * cname, *sname;
2757                 krb5_unparse_name(context, increds.client, &cname);
2758                 krb5_unparse_name(context, increds.server, &sname);
2759                 DebugPrintf("krb5_get_credentials() returned Service Principal Unknown\n"
2760                             "Trying again: getting tickets for \"%s\" and service \"%s\"\n", cname, sname);
2761                 krb5_free_unparsed_name(context,cname);
2762                 krb5_free_unparsed_name(context,sname);
2763             }
2764
2765             if (!code)
2766                 code = krb5_get_credentials(context, 0, cc, &increds, &k5creds);
2767             if (!code && !strlen(realm_of_cell))
2768                 copy_realm_of_ticket(context, realm_of_cell, sizeof(realm_of_cell), k5creds);
2769         }
2770     }
2771
2772     if (code) {
2773         DebugPrintf("krb5_get_credentials returns: %d\n", code);
2774         goto cleanup;
2775     }
2776
2777     /* This code inserts the entire K5 ticket into the token */
2778     memset(&aserver, '\0', sizeof(aserver));
2779     StringCbCopyN(aserver.name, sizeof(aserver.name),
2780                   ServiceName, sizeof(aserver.name) - 1);
2781     StringCbCopyN(aserver.cell, sizeof(aserver.cell),
2782                   CellName, sizeof(aserver.cell) - 1);
2783
2784     memset(&atoken, '\0', sizeof(atoken));
2785     atoken.kvno = RXKAD_TKT_TYPE_KERBEROS_V5;
2786     atoken.startTime = k5creds->times.starttime;
2787     atoken.endTime = k5creds->times.endtime;
2788     memcpy(&atoken.sessionKey,
2789             k5creds->session.keyvalue.data,
2790             k5creds->session.keyvalue.length);
2791     atoken.ticketLen = k5creds->ticket.length;
2792     memcpy(atoken.ticket, k5creds->ticket.data, atoken.ticketLen);
2793
2794   retry_gettoken5:
2795     rc = ktc_GetToken(&aserver, &btoken, sizeof(btoken), &aclient);
2796     if ( IsDebuggerPresent() ) {
2797         char message[256];
2798         StringCbPrintf(message, sizeof(message), "ktc_GetToken returns: %d\n", rc);
2799         OutputDebugString(message);
2800     }
2801     if (rc != 0 && rc != KTC_NOENT && rc != KTC_NOCELL) {
2802         if ( rc == KTC_NOCM && retry < 20 ) {
2803             Sleep(500);
2804             retry++;
2805             goto retry_gettoken5;
2806         }
2807         goto cleanup;
2808     }
2809
2810     if (atoken.kvno == btoken.kvno &&
2811          atoken.ticketLen == btoken.ticketLen &&
2812          !memcmp(&atoken.sessionKey, &btoken.sessionKey, sizeof(atoken.sessionKey)) &&
2813          !memcmp(atoken.ticket, btoken.ticket, atoken.ticketLen))
2814     {
2815         /* Success - Nothing to do */
2816         goto cleanup;
2817     }
2818
2819     // * Reset the "aclient" structure before we call ktc_SetToken.
2820     // * This structure was first set by the ktc_GetToken call when
2821     // * we were comparing whether identical tokens already existed.
2822
2823     StringCbCopy(aclient.name, sizeof(aclient.name),
2824                  krb5_principal_get_comp_string(context, k5creds->client, 0));
2825
2826     if ( krb5_principal_get_num_comp(context, k5creds->client) > 1 ) {
2827         StringCbCat(aclient.name, sizeof(aclient.name), ".");
2828         StringCbCat(aclient.name, sizeof(aclient.name),
2829                     krb5_principal_get_comp_string(context, k5creds->client, 1));
2830     }
2831     aclient.instance[0] = '\0';
2832
2833     StringCbCopyN(aclient.cell, sizeof(aclient.cell),
2834                   realm_of_cell, sizeof(aclient.cell) - 1);
2835
2836     /* For Khimaira, always append the realm name */
2837     StringCbCat(aclient.name, sizeof(aclient.name), "@");
2838     StringCbCat(aclient.name, sizeof(aclient.name),
2839                 krb5_principal_get_realm(context, k5creds->client));
2840
2841     GetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL, 0);
2842     if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
2843         ViceIDToUsername(aclient.name, realm_of_user, realm_of_cell, CellName,
2844                          &aclient, &aserver, &atoken);
2845
2846     if ( smbname ) {
2847         StringCbCopyN(aclient.smbname, sizeof(aclient.smbname),
2848                       smbname, sizeof(aclient.smbname) - 1);
2849     } else {
2850         aclient.smbname[0] = '\0';
2851     }
2852     if ( IsDebuggerPresent() ) {
2853         char message[256];
2854         StringCbPrintf(message, sizeof(message), "aclient.name: %s\n", aclient.name);
2855         OutputDebugString(message);
2856         StringCbPrintf(message, sizeof(message), "aclient.smbname: %s\n", aclient.smbname);
2857         OutputDebugString(message);
2858     }
2859
2860     rc = ktc_SetToken(&aserver, &atoken, &aclient, (aclient.smbname[0]?AFS_SETTOK_LOGON:0));
2861
2862 cleanup:
2863     if (client_principal)
2864         krb5_free_principal(context,client_principal);
2865     /* increds.client == client_principal */
2866     if (increds.server)
2867         krb5_free_principal(context,increds.server);
2868     if (cc && (cc != alt_cc))
2869         krb5_cc_close(context, cc);
2870     if (context && (context != alt_context))
2871         krb5_free_context(context);
2872     if (ak_cellconfig.linkedCell)
2873         free(ak_cellconfig.linkedCell);
2874
2875     return(rc? rc : code);
2876 }
2877
2878 /**************************************/
2879 /* afs_realm_of_cell():               */
2880 /**************************************/
2881 static char *
2882 afs_realm_of_cell(krb5_context context, struct afsconf_cell *cellconfig)
2883 {
2884     static char krbrlm[REALM_SZ+1]="";
2885     char ** realmlist=NULL;
2886     krb5_error_code r;
2887
2888     if (!cellconfig)
2889         return 0;
2890
2891     r = krb5_get_host_realm(context, cellconfig->hostName[0], &realmlist);
2892     if ( !r && realmlist && realmlist[0] ) {
2893         StringCbCopyN( krbrlm, sizeof(krbrlm),
2894                        realmlist[0], sizeof(krbrlm) - 1);
2895         krb5_free_host_realm(context, realmlist);
2896     }
2897
2898     if ( !krbrlm[0] )
2899     {
2900         char *s = krbrlm;
2901         char *t = cellconfig->name;
2902         int c;
2903
2904         while (c = *t++)
2905         {
2906             if (islower(c)) c=toupper(c);
2907             *s++ = c;
2908         }
2909         *s++ = 0;
2910     }
2911     return(krbrlm);
2912 }
2913
2914 /**************************************/
2915 /* KFW_AFS_get_cellconfig():          */
2916 /**************************************/
2917 int
2918 KFW_AFS_get_cellconfig(char *cell, struct afsconf_cell *cellconfig, char *local_cell)
2919 {
2920     int rc;
2921     char newcell[CELL_MAXNAMELEN+1];
2922     char linkedcell[CELL_MAXNAMELEN+1]="";
2923
2924     local_cell[0] = (char)0;
2925     memset(cellconfig, 0, sizeof(*cellconfig));
2926
2927     /* WIN32: cm_GetRootCellName(local_cell) - NOTE: no way to get max chars */
2928     if (rc = cm_GetRootCellName(local_cell))
2929     {
2930         return(rc);
2931     }
2932
2933     if (strlen(cell) == 0)
2934         StringCbCopy(cell, CELL_MAXNAMELEN, local_cell);
2935
2936     rc = cm_SearchCellRegistry(1, cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
2937     if (rc && rc != CM_ERROR_FORCE_DNS_LOOKUP)
2938         rc = cm_SearchCellFileEx(cell, newcell, linkedcell, get_cellconfig_callback, (void*)cellconfig);
2939     if (rc != 0) {
2940         int ttl;
2941         rc = cm_SearchCellByDNS(cell, newcell, &ttl, get_cellconfig_callback, (void*)cellconfig);
2942     }
2943
2944     if (rc == 0) {
2945         StringCbCopyN( cellconfig->name, sizeof(cellconfig->name),
2946                        newcell, sizeof(cellconfig->name) - 1);
2947         if (linkedcell[0])
2948             cellconfig->linkedCell = strdup(linkedcell);
2949     }
2950     return rc;
2951 }
2952
2953 /**************************************/
2954 /* get_cellconfig_callback():         */
2955 /**************************************/
2956 static long
2957 get_cellconfig_callback(void *cellconfig, struct sockaddr_in *addrp, char *namep, unsigned short ipRank)
2958 {
2959     struct afsconf_cell *cc = (struct afsconf_cell *)cellconfig;
2960
2961     cc->hostAddr[cc->numServers] = *addrp;
2962     StringCbCopyN( cc->hostName[cc->numServers], sizeof(cc->hostName[cc->numServers]),
2963                    namep, sizeof(cc->hostName[cc->numServers]) - 1);
2964     cc->numServers++;
2965     return(0);
2966 }
2967
2968
2969 /**************************************/
2970 /* KFW_AFS_error():                  */
2971 /**************************************/
2972 void
2973 KFW_AFS_error(LONG rc, LPCSTR FailedFunctionName)
2974 {
2975     char message[256];
2976     const char *errText;
2977
2978     // Using AFS defines as error messages for now, until Transarc
2979     // gets back to me with "string" translations of each of these
2980     // const. defines.
2981     if (rc == KTC_ERROR)
2982       errText = "KTC_ERROR";
2983     else if (rc == KTC_TOOBIG)
2984       errText = "KTC_TOOBIG";
2985     else if (rc == KTC_INVAL)
2986       errText = "KTC_INVAL";
2987     else if (rc == KTC_NOENT)
2988       errText = "KTC_NOENT";
2989     else if (rc == KTC_PIOCTLFAIL)
2990       errText = "KTC_PIOCTLFAIL";
2991     else if (rc == KTC_NOPIOCTL)
2992       errText = "KTC_NOPIOCTL";
2993     else if (rc == KTC_NOCELL)
2994       errText = "KTC_NOCELL";
2995     else if (rc == KTC_NOCM)
2996       errText = "KTC_NOCM: The service, Transarc AFS Daemon, most likely is not started!";
2997     else
2998       errText = "Unknown error!";
2999
3000     StringCbPrintf(message, sizeof(message), "%s (0x%x)\n(%s failed)", errText, rc, FailedFunctionName);
3001
3002     if ( IsDebuggerPresent() ) {
3003         OutputDebugString(message);
3004         OutputDebugString("\n");
3005     }
3006     MessageBox(NULL, message, "AFS", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND);
3007     return;
3008 }
3009
3010 static DWORD
3011 GetServiceStatus(
3012     LPSTR lpszMachineName,
3013     LPSTR lpszServiceName,
3014     DWORD *lpdwCurrentState)
3015 {
3016     DWORD           hr               = NOERROR;
3017     SC_HANDLE       schSCManager     = NULL;
3018     SC_HANDLE       schService       = NULL;
3019     DWORD           fdwDesiredAccess = 0;
3020     SERVICE_STATUS  ssServiceStatus  = {0};
3021     BOOL            fRet             = FALSE;
3022
3023     *lpdwCurrentState = 0;
3024
3025     fdwDesiredAccess = GENERIC_READ;
3026
3027     schSCManager = OpenSCManager(lpszMachineName,
3028                                  NULL,
3029                                  fdwDesiredAccess);
3030
3031     if(schSCManager == NULL)
3032     {
3033         hr = GetLastError();
3034         goto cleanup;
3035     }
3036
3037     schService = OpenService(schSCManager,
3038                              lpszServiceName,
3039                              fdwDesiredAccess);
3040
3041     if(schService == NULL)
3042     {
3043         hr = GetLastError();
3044         goto cleanup;
3045     }
3046
3047     fRet = QueryServiceStatus(schService,
3048                               &ssServiceStatus);
3049
3050     if(fRet == FALSE)
3051     {
3052         hr = GetLastError();
3053         goto cleanup;
3054     }
3055
3056     *lpdwCurrentState = ssServiceStatus.dwCurrentState;
3057
3058 cleanup:
3059
3060     CloseServiceHandle(schService);
3061     CloseServiceHandle(schSCManager);
3062
3063     return(hr);
3064 }
3065
3066 BOOL KFW_probe_kdc(struct afsconf_cell * cellconfig)
3067 {
3068     krb5_context context = NULL;
3069     krb5_ccache cc = NULL;
3070     krb5_error_code code;
3071     krb5_data pwdata;
3072     const char * realm = NULL;
3073     krb5_principal principal = NULL;
3074     char * pname = NULL;
3075     char   password[PROBE_PASSWORD_LEN+1];
3076     BOOL serverReachable = 0;
3077
3078     code = krb5_init_context(&context);
3079     if (code) goto cleanup;
3080
3081
3082     realm = afs_realm_of_cell(context, cellconfig);  // do not free
3083
3084     code = krb5_build_principal(context, &principal, (int)strlen(realm),
3085                                   realm, PROBE_USERNAME, NULL, NULL);
3086     if ( code ) goto cleanup;
3087
3088     code = KFW_get_ccache(context, principal, &cc);
3089     if ( code ) goto cleanup;
3090
3091     code = krb5_unparse_name(context, principal, &pname);
3092     if ( code ) goto cleanup;
3093
3094     pwdata.data = password;
3095     pwdata.length = PROBE_PASSWORD_LEN;
3096     krb5_c_random_make_octets(context, &pwdata);
3097     {
3098         int i;
3099         for ( i=0 ; i<PROBE_PASSWORD_LEN ; i++ )
3100             if (password[i] == '\0')
3101                 password[i] = 'x';
3102     }
3103     password[PROBE_PASSWORD_LEN] = '\0';
3104
3105     code = KFW_kinit(NULL, NULL, HWND_DESKTOP,
3106                       pname,
3107                       password,
3108                       5,
3109                       0,
3110                       0,
3111                       0,
3112                       1,
3113                       0);
3114     switch ( code ) {
3115     case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
3116     case KRB5KDC_ERR_CLIENT_REVOKED:
3117     case KRB5KDC_ERR_CLIENT_NOTYET:
3118     case KRB5KDC_ERR_PREAUTH_FAILED:
3119     case KRB5KDC_ERR_PREAUTH_REQUIRED:
3120     case KRB5KDC_ERR_PADATA_TYPE_NOSUPP:
3121         serverReachable = TRUE;
3122         break;
3123     default:
3124         serverReachable = FALSE;
3125     }
3126
3127   cleanup:
3128     if ( pname )
3129         krb5_free_unparsed_name(context,pname);
3130     if ( principal )
3131         krb5_free_principal(context,principal);
3132     if (cc)
3133         krb5_cc_close(context,cc);
3134     if (context)
3135         krb5_free_context(context);
3136
3137     return serverReachable;
3138 }
3139
3140 BOOL
3141 KFW_AFS_get_lsa_principal(char * szUser, DWORD *dwSize)
3142 {
3143     krb5_context   context = NULL;
3144     krb5_error_code code;
3145     krb5_ccache mslsa_ccache=NULL;
3146     krb5_principal princ = NULL;
3147     char * pname = NULL;
3148     BOOL success = 0;
3149
3150     if (!KFW_is_available())
3151         return FALSE;
3152
3153     if (code = krb5_init_context(&context))
3154         goto cleanup;
3155
3156     if (code = krb5_cc_resolve(context, "MSLSA:", &mslsa_ccache))
3157         goto cleanup;
3158
3159     if (code = krb5_cc_get_principal(context, mslsa_ccache, &princ))
3160         goto cleanup;
3161
3162     if (code = krb5_unparse_name(context, princ, &pname))
3163         goto cleanup;
3164
3165     if ( strlen(pname) < *dwSize ) {
3166         StringCbCopyN(szUser, *dwSize, pname, (*dwSize) - 1);
3167         success = 1;
3168     }
3169     *dwSize = (DWORD)strlen(pname);
3170
3171   cleanup:
3172     if (pname)
3173         krb5_free_unparsed_name(context, pname);
3174
3175     if (princ)
3176         krb5_free_principal(context, princ);
3177
3178     if (mslsa_ccache)
3179         krb5_cc_close(context, mslsa_ccache);
3180
3181     if (context)
3182         krb5_free_context(context);
3183     return success;
3184 }
3185
3186 int
3187 KFW_AFS_set_file_cache_dacl(char *filename, HANDLE hUserToken)
3188 {
3189     // SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_SID_AUTHORITY;
3190     PSID pSystemSID = NULL;
3191     DWORD SystemSIDlength = 0, UserSIDlength = 0;
3192     PACL ccacheACL = NULL;
3193     DWORD ccacheACLlength = 0;
3194     PTOKEN_USER pTokenUser = NULL;
3195     DWORD retLen;
3196     DWORD gle;
3197     int ret = 0;
3198
3199     if (!filename) {
3200         return 1;
3201     }
3202
3203     /* Get System SID */
3204     if (!ConvertStringSidToSid("S-1-5-18", &pSystemSID)) {
3205         ret = 1;
3206         goto cleanup;
3207     }
3208
3209     /* Create ACL */
3210     SystemSIDlength = GetLengthSid(pSystemSID);
3211     ccacheACLlength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE)
3212         + SystemSIDlength - sizeof(DWORD);
3213
3214     if (hUserToken) {
3215         if (!GetTokenInformation(hUserToken, TokenUser, NULL, 0, &retLen))
3216         {
3217             if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
3218                 pTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
3219
3220                 GetTokenInformation(hUserToken, TokenUser, pTokenUser, retLen, &retLen);
3221             }
3222         }
3223
3224         if (pTokenUser) {
3225             UserSIDlength = GetLengthSid(pTokenUser->User.Sid);
3226
3227             ccacheACLlength += sizeof(ACCESS_ALLOWED_ACE) + UserSIDlength
3228                 - sizeof(DWORD);
3229         }
3230     }
3231
3232     ccacheACL = (PACL) LocalAlloc(LPTR, ccacheACLlength);
3233     if (!ccacheACL) {
3234         ret = 1;
3235         goto cleanup;
3236      }
3237     InitializeAcl(ccacheACL, ccacheACLlength, ACL_REVISION);
3238     AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3239                          STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3240                          pSystemSID);
3241     if (pTokenUser) {
3242         AddAccessAllowedAceEx(ccacheACL, ACL_REVISION, 0,
3243                              STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
3244                              pTokenUser->User.Sid);
3245         if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3246                                    DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3247                                    NULL,
3248                                    NULL,
3249                                    ccacheACL,
3250                                    NULL)) {
3251             gle = GetLastError();
3252             if (gle != ERROR_NO_TOKEN)
3253                 ret = 1;
3254         }
3255         if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3256                                    OWNER_SECURITY_INFORMATION,
3257                                    pTokenUser->User.Sid,
3258                                    NULL,
3259                                    NULL,
3260                                    NULL)) {
3261             gle = GetLastError();
3262             if (gle != ERROR_NO_TOKEN)
3263                 ret = 1;
3264         }
3265     } else {
3266         if (!SetNamedSecurityInfo( filename, SE_FILE_OBJECT,
3267                                    DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
3268                                    NULL,
3269                                    NULL,
3270                                    ccacheACL,
3271                                    NULL)) {
3272             gle = GetLastError();
3273             if (gle != ERROR_NO_TOKEN)
3274                 ret = 1;
3275         }
3276     }
3277
3278   cleanup:
3279     if (pSystemSID)
3280         LocalFree(pSystemSID);
3281     if (pTokenUser)
3282         LocalFree(pTokenUser);
3283     if (ccacheACL)
3284         LocalFree(ccacheACL);
3285     return ret;
3286 }
3287
3288 int
3289 KFW_AFS_obtain_user_temp_directory(HANDLE hUserToken, char *newfilename, int size)
3290 {
3291     int  retval = 0;
3292     DWORD dwSize = size-1;      /* leave room for nul */
3293     DWORD dwLen  = 0;
3294
3295     if (!hUserToken || !newfilename || size <= 0)
3296         return 1;
3297
3298      *newfilename = '\0';
3299
3300      dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TEMP%", newfilename, dwSize);
3301      if ( !dwLen || dwLen > dwSize )
3302         dwLen = ExpandEnvironmentStringsForUser(hUserToken, "%TMP%", newfilename, dwSize);
3303      if ( !dwLen || dwLen > dwSize )
3304         return 1;
3305
3306      newfilename[dwSize] = '\0';
3307     return 0;
3308 }
3309
3310 void
3311 KFW_AFS_copy_cache_to_system_file(char * user, char * szLogonId)
3312 {
3313     char filename[MAX_PATH] = "";
3314     DWORD count;
3315     char cachename[MAX_PATH + 8] = "FILE:";
3316     krb5_context                context = NULL;
3317     krb5_error_code             code;
3318     krb5_principal              princ = NULL;
3319     krb5_ccache                 cc  = NULL;
3320     krb5_ccache                 ncc = NULL;
3321
3322     if (!user || !szLogonId)
3323         return;
3324
3325     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
3326     if ( count > sizeof(filename) || count == 0 ) {
3327         GetWindowsDirectory(filename, sizeof(filename));
3328     }
3329
3330     if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) )
3331         return;
3332
3333     StringCbCat( filename, sizeof(filename), "\\");
3334     StringCbCat( filename, sizeof(filename), szLogonId);
3335
3336     StringCbCat( cachename, sizeof(cachename), filename);
3337
3338     DeleteFile(filename);
3339
3340     code = krb5_init_context(&context);
3341     if (code) goto cleanup;
3342
3343     code = krb5_parse_name(context, user, &princ);
3344     if (code) goto cleanup;
3345
3346     code = KFW_get_ccache(context, princ, &cc);
3347     if (code) goto cleanup;
3348
3349     code = krb5_cc_resolve(context, cachename, &ncc);
3350     if (code) goto cleanup;
3351
3352     code = krb5_cc_initialize(context, ncc, princ);
3353     if (code) goto cleanup;
3354
3355     code = KFW_AFS_set_file_cache_dacl(filename, NULL);
3356     if (code) goto cleanup;
3357
3358     code = krb5_cc_copy_creds(context,cc,ncc);
3359
3360   cleanup:
3361     if ( cc ) {
3362         krb5_cc_close(context, cc);
3363         cc = 0;
3364     }
3365     if ( ncc ) {
3366         krb5_cc_close(context, ncc);
3367         ncc = 0;
3368     }
3369     if ( princ ) {
3370         krb5_free_principal(context, princ);
3371         princ = 0;
3372     }
3373
3374     if (context)
3375         krb5_free_context(context);
3376 }
3377
3378 int
3379 KFW_AFS_copy_file_cache_to_default_cache(char * filename)
3380 {
3381     char cachename[MAX_PATH + 8] = "FILE:";
3382     krb5_context                context = NULL;
3383     krb5_error_code             code;
3384     krb5_principal              princ = NULL;
3385     krb5_ccache                 cc  = NULL;
3386     krb5_ccache                 ncc = NULL;
3387     int retval = 1;
3388
3389     if (!filename)
3390         return 1;
3391
3392     if ( strlen(filename) + sizeof("FILE:") > sizeof(cachename) )
3393         return 1;
3394
3395     code = krb5_init_context(&context);
3396     if (code) return 1;
3397
3398     StringCbCat( cachename, sizeof(cachename), filename);
3399
3400     code = krb5_cc_resolve(context, cachename, &cc);
3401     if (code) goto cleanup;
3402
3403     code = krb5_cc_get_principal(context, cc, &princ);
3404
3405     code = krb5_cc_default(context, &ncc);
3406     if (!code) {
3407         code = krb5_cc_initialize(context, ncc, princ);
3408
3409         if (!code)
3410             code = krb5_cc_copy_creds(context,cc,ncc);
3411     }
3412     if ( ncc ) {
3413         krb5_cc_close(context, ncc);
3414         ncc = 0;
3415     }
3416
3417     retval=0;   /* success */
3418
3419   cleanup:
3420     if ( cc ) {
3421         krb5_cc_close(context, cc);
3422         cc = 0;
3423     }
3424
3425     DeleteFile(filename);
3426
3427     if ( princ ) {
3428         krb5_free_principal(context, princ);
3429         princ = 0;
3430     }
3431
3432     if (context)
3433         krb5_free_context(context);
3434
3435     return 0;
3436 }
3437
3438 /* We are including this
3439
3440 /* Ticket lifetime.  This defines the table used to lookup lifetime for the
3441    fixed part of rande of the one byte lifetime field.  Values less than 0x80
3442    are intrpreted as the number of 5 minute intervals.  Values from 0x80 to
3443    0xBF should be looked up in this table.  The value of 0x80 is the same using
3444    both methods: 10 and two-thirds hours .  The lifetime of 0xBF is 30 days.
3445    The intervening values of have a fixed ratio of roughly 1.06914.  The value
3446    oxFF is defined to mean a ticket has no expiration time.  This should be
3447    used advisedly since individual servers may impose defacto upperbounds on
3448    ticket lifetimes. */
3449
3450 #define TKTLIFENUMFIXED 64
3451 #define TKTLIFEMINFIXED 0x80
3452 #define TKTLIFEMAXFIXED 0xBF
3453 #define TKTLIFENOEXPIRE 0xFF
3454 #define MAXTKTLIFETIME  (30*24*3600)    /* 30 days */
3455
3456 static const int tkt_lifetimes[TKTLIFENUMFIXED] = {
3457     38400,                      /* 10.67 hours, 0.44 days */
3458     41055,                      /* 11.40 hours, 0.48 days */
3459     43894,                      /* 12.19 hours, 0.51 days */
3460     46929,                      /* 13.04 hours, 0.54 days */
3461     50174,                      /* 13.94 hours, 0.58 days */
3462     53643,                      /* 14.90 hours, 0.62 days */
3463     57352,                      /* 15.93 hours, 0.66 days */
3464     61318,                      /* 17.03 hours, 0.71 days */
3465     65558,                      /* 18.21 hours, 0.76 days */
3466     70091,                      /* 19.47 hours, 0.81 days */
3467     74937,                      /* 20.82 hours, 0.87 days */
3468     80119,                      /* 22.26 hours, 0.93 days */
3469     85658,                      /* 23.79 hours, 0.99 days */
3470     91581,                      /* 25.44 hours, 1.06 days */
3471     97914,                      /* 27.20 hours, 1.13 days */
3472     104684,                     /* 29.08 hours, 1.21 days */
3473     111922,                     /* 31.09 hours, 1.30 days */
3474     119661,                     /* 33.24 hours, 1.38 days */
3475     127935,                     /* 35.54 hours, 1.48 days */
3476     136781,                     /* 37.99 hours, 1.58 days */
3477     146239,                     /* 40.62 hours, 1.69 days */
3478     156350,                     /* 43.43 hours, 1.81 days */
3479     167161,                     /* 46.43 hours, 1.93 days */
3480     178720,                     /* 49.64 hours, 2.07 days */
3481     191077,                     /* 53.08 hours, 2.21 days */
3482     204289,                     /* 56.75 hours, 2.36 days */
3483     218415,                     /* 60.67 hours, 2.53 days */
3484     233517,                     /* 64.87 hours, 2.70 days */
3485     249664,                     /* 69.35 hours, 2.89 days */
3486     266926,                     /* 74.15 hours, 3.09 days */
3487     285383,                     /* 79.27 hours, 3.30 days */
3488     305116,                     /* 84.75 hours, 3.53 days */
3489     326213,                     /* 90.61 hours, 3.78 days */
3490     348769,                     /* 96.88 hours, 4.04 days */
3491     372885,                     /* 103.58 hours, 4.32 days */
3492     398668,                     /* 110.74 hours, 4.61 days */
3493     426234,                     /* 118.40 hours, 4.93 days */
3494     455705,                     /* 126.58 hours, 5.27 days */
3495     487215,                     /* 135.34 hours, 5.64 days */
3496     520904,                     /* 144.70 hours, 6.03 days */
3497     556921,                     /* 154.70 hours, 6.45 days */
3498     595430,                     /* 165.40 hours, 6.89 days */
3499     636601,                     /* 176.83 hours, 7.37 days */
3500     680618,                     /* 189.06 hours, 7.88 days */
3501     727680,                     /* 202.13 hours, 8.42 days */
3502     777995,                     /* 216.11 hours, 9.00 days */
3503     831789,                     /* 231.05 hours, 9.63 days */
3504     889303,                     /* 247.03 hours, 10.29 days */
3505     950794,                     /* 264.11 hours, 11.00 days */
3506     1016537,                    /* 282.37 hours, 11.77 days */
3507     1086825,                    /* 301.90 hours, 12.58 days */
3508     1161973,                    /* 322.77 hours, 13.45 days */
3509     1242318,                    /* 345.09 hours, 14.38 days */
3510     1328218,                    /* 368.95 hours, 15.37 days */
3511     1420057,                    /* 394.46 hours, 16.44 days */
3512     1518247,                    /* 421.74 hours, 17.57 days */
3513     1623226,                    /* 450.90 hours, 18.79 days */
3514     1735464,                    /* 482.07 hours, 20.09 days */
3515     1855462,                    /* 515.41 hours, 21.48 days */
3516     1983758,                    /* 551.04 hours, 22.96 days */
3517     2120925,                    /* 589.15 hours, 24.55 days */
3518     2267576,                    /* 629.88 hours, 26.25 days */
3519     2424367,                    /* 673.44 hours, 28.06 days */
3520     2592000
3521 };                              /* 720.00 hours, 30.00 days */
3522
3523 /* life_to_time - takes a start time and a Kerberos standard lifetime char and
3524  * returns the corresponding end time.  There are four simple cases to be
3525  * handled.  The first is a life of 0xff, meaning no expiration, and results in
3526  * an end time of 0xffffffff.  The second is when life is less than the values
3527  * covered by the table.  In this case, the end time is the start time plus the
3528  * number of 5 minute intervals specified by life.  The third case returns
3529  * start plus the MAXTKTLIFETIME if life is greater than TKTLIFEMAXFIXED.  The
3530  * last case, uses the life value (minus TKTLIFEMINFIXED) as an index into the
3531  * table to extract the lifetime in seconds, which is added to start to produce
3532  * the end time. */
3533
3534 afs_uint32
3535 life_to_time(afs_uint32 start, unsigned char life)
3536 {
3537     int realLife;
3538
3539     if (life == TKTLIFENOEXPIRE)
3540         return NEVERDATE;
3541     if (life < TKTLIFEMINFIXED)
3542         return start + life * 5 * 60;
3543     if (life > TKTLIFEMAXFIXED)
3544         return start + MAXTKTLIFETIME;
3545     realLife = tkt_lifetimes[life - TKTLIFEMINFIXED];
3546     return start + realLife;
3547 }
3548
3549 /* time_to_life - takes start and end times for the ticket and returns a
3550  * Kerberos standard lifetime char possibily using the tkt_lifetimes table for
3551  * lifetimes above 127*5minutes.  First, the special case of (end ==
3552  * 0xffffffff) is handled to mean no expiration.  Then negative lifetimes and
3553  * those greater than the maximum ticket lifetime are rejected.  Then lifetimes
3554  * less than the first table entry are handled by rounding the requested
3555  * lifetime *up* to the next 5 minute interval.  The final step is to search
3556  * the table for the smallest entry *greater than or equal* to the requested
3557  * entry.  The actual code is prepared to handle the case where the table is
3558  * unordered but that it an unnecessary frill. */
3559
3560 static unsigned char
3561 time_to_life(afs_uint32 start, afs_uint32 end)
3562 {
3563     int lifetime = end - start;
3564     int best, best_i;
3565     int i;
3566
3567     if (end == NEVERDATE)
3568         return TKTLIFENOEXPIRE;
3569     if ((lifetime > MAXKTCTICKETLIFETIME) || (lifetime <= 0))
3570         return 0;
3571     if (lifetime < tkt_lifetimes[0])
3572         return (lifetime + 5 * 60 - 1) / (5 * 60);
3573     best_i = -1;
3574     best = MAXKTCTICKETLIFETIME;
3575     for (i = 0; i < TKTLIFENUMFIXED; i++)
3576         if (tkt_lifetimes[i] >= lifetime) {
3577             int diff = tkt_lifetimes[i] - lifetime;
3578             if (diff < best) {
3579                 best = diff;
3580                 best_i = i;
3581             }
3582         }
3583     if (best_i < 0)
3584         return 0;
3585     return best_i + TKTLIFEMINFIXED;
3586 }
3587
3588 DWORD KFW_get_default_mslsa_import(krb5_context context)
3589 {
3590     static const char * lsh_settings_key = "";
3591     static const char * lsh_mslsa_value = "";
3592     DWORD import = 0;
3593     HKEY hKey;
3594     DWORD dwCount;
3595     LONG rc;
3596
3597     rc = RegOpenKeyEx(HKEY_CURRENT_USER, lsh_settings_key, 0, KEY_QUERY_VALUE, &hKey);
3598     if (rc)
3599         return import;
3600
3601     dwCount = sizeof(DWORD);
3602     rc = RegQueryValueEx(hKey, lsh_mslsa_value, 0, 0, (LPBYTE) &import, &dwCount);
3603     RegCloseKey(hKey);
3604
3605     if (rc == 0)
3606         return import;
3607
3608     rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lsh_settings_key, 0, KEY_QUERY_VALUE, &hKey);
3609     if (rc)
3610         return import;
3611
3612     dwCount = sizeof(DWORD);
3613     rc = RegQueryValueEx(hKey, lsh_mslsa_value, 0, 0, (LPBYTE) &import, &dwCount);
3614     RegCloseKey(hKey);
3615
3616     return import;
3617 }
3618
3619 DWORD KFW_get_default_lifetime(krb5_context context, const char * realm)
3620 {
3621     static const char * lifetime_val_name = "ticket_lifetime";
3622     time_t t = 0;
3623
3624     krb5_appdefault_time(context, "aklog", realm, lifetime_val_name, 0, &t);
3625
3626     if (t == 0)
3627         t = krb5_config_get_time_default(context, NULL, 0,
3628                                          "realms", realm, lifetime_val_name, NULL);
3629
3630     if (t == 0)
3631         t = krb5_config_get_time_default(context, NULL, 0,
3632                                          "libdefaults", lifetime_val_name, NULL);
3633
3634     if (t == 0)
3635         t = 10 * 60 * 60;
3636
3637     return (DWORD) t;
3638 }
3639