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