506ea71bd4912a70ddc71aadab77b13fed674121
[openafs.git] / src / WINNT / afsd / afslogon.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include "afslogon.h"
11
12 #include <io.h>
13 #include <sys/stat.h>
14 #include <sys/types.h>
15 #include <fcntl.h>
16
17 #include <winsock2.h>
18 #include <lm.h>
19 #include <nb30.h>
20
21 #include <afs/param.h>
22 #include <afs/stds.h>
23 #include <afs/pioctl_nt.h>
24 #include <afs/kautils.h>
25
26 #include "afsd.h"
27 #include "cm_config.h"
28 #include "krb.h"
29 #include "afskfw.h"
30 #include "lanahelper.h"
31
32 #include <WINNT\afsreg.h>
33
34 DWORD TraceOption = 0;
35
36 HANDLE hDLL;
37
38 WSADATA WSAjunk;
39 #define AFS_LOGON_EVENT_NAME TEXT("AFS Logon")
40
41 void DebugEvent0(char *a) 
42 {
43     HANDLE h; char *ptbuf[1];
44     
45     if (!ISLOGONTRACE(TraceOption))
46         return;
47     
48     h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
49     ptbuf[0] = a;
50     ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
51     DeregisterEventSource(h);
52 }
53
54 #define MAXBUF_ 512
55 void DebugEvent(char *b,...) 
56 {
57     HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
58     va_list marker;
59
60     if (!ISLOGONTRACE(TraceOption))
61         return;
62
63     h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
64     va_start(marker,b);
65     StringCbVPrintf(buf, MAXBUF_+1,b,marker);
66     buf[MAXBUF_] = '\0';
67     ptbuf[0] = buf;
68     ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
69     DeregisterEventSource(h);
70     va_end(marker);
71 }
72
73 static HANDLE hInitMutex = NULL;
74 static BOOL bInit = FALSE;
75
76 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
77 {
78     hDLL = dll;
79     switch (reason) {
80     case DLL_PROCESS_ATTACH:
81         /* Initialization Mutex */
82         hInitMutex = CreateMutex(NULL, FALSE, NULL);
83         break;
84
85     case DLL_PROCESS_DETACH:
86         CloseHandle(hInitMutex);
87         break;
88
89     case DLL_THREAD_ATTACH:
90     case DLL_THREAD_DETACH:
91     default:
92         /* Everything else succeeds but does nothing. */
93         break;
94     }
95
96     return TRUE;
97 }
98
99 void AfsLogonInit(void)
100 {
101     if ( bInit == FALSE ) {
102         if ( WaitForSingleObject( hInitMutex, INFINITE ) == WAIT_OBJECT_0 ) {
103             if ( bInit == FALSE ) {
104                 rx_Init(0);
105                 initAFSDirPath();
106                 ka_Init(0);
107                 bInit = TRUE;
108             }
109             ReleaseMutex(hInitMutex);
110         }
111     }
112 }
113
114 CHAR *GenRandomName(CHAR *pbuf)
115 {
116     int i;
117     srand( (unsigned)time( NULL ) );
118     for (i=0;i<MAXRANDOMNAMELEN-1;i++)
119         pbuf[i]='a'+(rand() % 26);
120     pbuf[MAXRANDOMNAMELEN-1]=0;
121     return pbuf;
122 }
123
124 BOOLEAN AFSWillAutoStart(void)
125 {
126     SC_HANDLE scm;
127     SC_HANDLE svc;
128     BOOLEAN flag;
129     BOOLEAN result = FALSE;
130     LPQUERY_SERVICE_CONFIG pConfig = NULL;
131     DWORD BufSize;
132     LONG status;
133
134     /* Open services manager */
135     scm = OpenSCManager(NULL, NULL, GENERIC_READ);
136     if (!scm) return FALSE;
137
138     /* Open AFSD service */
139     svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
140     if (!svc)
141         goto close_scm;
142
143     /* Query AFSD service config, first just to get buffer size */
144     /* Expected to fail, so don't test return value */
145     (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
146     status = GetLastError();
147     if (status != ERROR_INSUFFICIENT_BUFFER)
148         goto close_svc;
149
150     /* Allocate buffer */
151     pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
152     if (!pConfig)
153         goto close_svc;
154
155     /* Query AFSD service config, this time for real */
156     flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
157     if (!flag)
158         goto free_pConfig;
159
160     /* Is it autostart? */
161     if (pConfig->dwStartType < SERVICE_DEMAND_START)
162         result = TRUE;
163
164   free_pConfig:
165     GlobalFree(pConfig);
166   close_svc:
167     CloseServiceHandle(svc);
168   close_scm:
169     CloseServiceHandle(scm);
170
171     return result;
172 }
173
174 DWORD MapAuthError(DWORD code)
175 {
176     switch (code) {
177         /* Unfortunately, returning WN_NO_NETWORK results in the MPR abandoning
178          * logon scripts for all credential managers, although they will still
179          * receive logon notifications.  Since we don't want this, we return
180          * WN_SUCCESS.  This is highly undesirable, but we also don't want to
181          * break other network providers.
182          */
183  /* case KTC_NOCM:
184     case KTC_NOCMRPC:
185     return WN_NO_NETWORK; */
186     default: return WN_SUCCESS;
187   }
188 }
189
190 DWORD APIENTRY NPGetCaps(DWORD index)
191 {
192     switch (index) {
193     case WNNC_NET_TYPE:
194         /* Don't have our own type; use somebody else's. */
195         return WNNC_NET_SUN_PC_NFS;
196
197     case WNNC_START:
198         /* Say we are already started, even though we might wait after we receive NPLogonNotify */
199         return 1;
200
201     default:
202         return 0;
203     }
204 }       
205
206 NET_API_STATUS 
207 NetUserGetProfilePath( LPCWSTR Domain, LPCWSTR UserName, char * profilePath, 
208                        DWORD profilePathLen )
209 {
210     NET_API_STATUS code;
211     LPWSTR ServerName = NULL;
212     LPUSER_INFO_3 p3 = NULL;
213
214     NetGetAnyDCName(NULL, Domain, (LPBYTE *)&ServerName);
215     /* if NetGetAnyDCName fails, ServerName == NULL
216      * NetUserGetInfo will obtain local user information 
217      */
218     code = NetUserGetInfo(ServerName, UserName, 3, (LPBYTE *)&p3);
219     if (code == NERR_Success)
220     {
221         code = NERR_UserNotFound;
222         if (p3) {
223             if (p3->usri3_profile) {
224                 DWORD len = lstrlenW(p3->usri3_profile);
225                 if (len > 0) {
226                     /* Convert From Unicode to ANSI (UTF-8 for future) */
227                     len = len < profilePathLen ? len : profilePathLen - 1;
228                     WideCharToMultiByte(CP_UTF8, 0, p3->usri3_profile, len, profilePath, len, NULL, NULL);
229                     profilePath[len] = '\0';
230                     code = NERR_Success;
231                 }
232             }
233             NetApiBufferFree(p3);
234         }
235     }
236     if (ServerName) 
237         NetApiBufferFree(ServerName);
238     return code;
239 }
240
241 BOOL IsServiceRunning (void)
242 {
243     SERVICE_STATUS Status;
244     SC_HANDLE hManager;
245     memset (&Status, 0x00, sizeof(Status));
246     Status.dwCurrentState = SERVICE_STOPPED;
247
248     if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
249     {
250         SC_HANDLE hService;
251         if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
252         {
253             QueryServiceStatus (hService, &Status);
254             CloseServiceHandle (hService);
255         }
256
257         CloseServiceHandle (hManager);
258     }
259     DebugEvent("AFS AfsLogon - Test Service Running","Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
260     return (Status.dwCurrentState == SERVICE_RUNNING);
261 }   
262
263 BOOL IsServiceStartPending (void)
264 {
265     SERVICE_STATUS Status;
266     SC_HANDLE hManager;
267     memset (&Status, 0x00, sizeof(Status));
268     Status.dwCurrentState = SERVICE_STOPPED;
269
270     if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
271     {
272         SC_HANDLE hService;
273         if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
274         {
275             QueryServiceStatus (hService, &Status);
276             CloseServiceHandle (hService);
277         }
278
279         CloseServiceHandle (hManager);
280     }
281     DebugEvent("AFS AfsLogon - Test Service Start Pending","Return Code[%x] ?Start Pending[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_START_PENDING));
282     return (Status.dwCurrentState == SERVICE_START_PENDING);
283 }   
284
285 /* LOOKUPKEYCHAIN: macro to look up the value in the list of keys in order until it's found
286    v:variable to receive value (reference type)
287    t:type
288    d:default, in case the value isn't on any of the keys
289    n:name of value */
290 #define LOOKUPKEYCHAIN(v,t,d,n) \
291         do { \
292                 rv = ~ERROR_SUCCESS; \
293                 dwType = t; \
294                 if(hkDom) { \
295                         dwSize = sizeof(v); \
296                         rv = RegQueryValueEx(hkDom, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
297                         if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDom with type [%d]", dwType); \
298                 } \
299                 if(hkDoms && (rv != ERROR_SUCCESS || dwType != t)) { \
300                         dwSize = sizeof(v); \
301                         rv = RegQueryValueEx(hkDoms, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
302                         if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDoms with type [%d]", dwType); \
303                 } \
304                 if(hkNp && (rv != ERROR_SUCCESS || dwType != t)) { \
305                         dwSize = sizeof(v); \
306                         rv = RegQueryValueEx(hkNp, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
307                         if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkNp with type [%d]", dwType); \
308                 } \
309                 if(rv != ERROR_SUCCESS || dwType != t) { \
310                         v = d; \
311                         DebugEvent(#v " being set to default"); \
312                 } \
313         } while(0)
314
315 /* Get domain specific configuration info.  We are returning void because if anything goes wrong
316    we just return defaults.
317  */
318 void 
319 GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
320     HKEY hkParm = NULL; /* Service parameter */
321     HKEY hkNp = NULL;   /* network provider key */
322     HKEY hkDoms = NULL; /* domains key */
323     HKEY hkDom = NULL;  /* DOMAINS/domain key */
324     HKEY hkTemp = NULL;
325     LONG rv;
326     DWORD dwSize;
327     DWORD dwType;
328     DWORD dwDummy;
329     char computerName[MAX_COMPUTERNAME_LENGTH + 1];
330     char *effDomain;
331
332     memset(opt, 0, sizeof(LogonOptions_t));
333
334     DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
335     /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
336     opt->flags = LOGON_FLAG_REMOTE;
337     if(domain) {
338         dwSize = MAX_COMPUTERNAME_LENGTH;
339         if(GetComputerName(computerName, &dwSize)) {
340             if(!stricmp(computerName, domain)) {
341                 effDomain = "LOCALHOST";
342                 opt->flags = LOGON_FLAG_LOCAL;
343             }
344             else
345                 effDomain = domain;
346         }
347     } else
348         effDomain = NULL;
349
350     rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, KEY_READ, &hkParm );
351     if(rv != ERROR_SUCCESS) {
352         hkParm = NULL;
353         DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
354     }
355
356     rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PROVIDER_SUBKEY, 0, KEY_READ, &hkNp );
357     if(rv != ERROR_SUCCESS) {
358         hkNp = NULL;
359         DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
360     }
361
362     if(hkNp) {
363         rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
364         if( rv != ERROR_SUCCESS ) {
365             hkDoms = NULL;
366             DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
367         }
368     }
369
370     if(hkDoms && effDomain) {
371         rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
372         if( rv != ERROR_SUCCESS ) {
373             hkDom = NULL;
374             DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
375             /* If none of the domains match, we shouldn't use the domain key either */
376             RegCloseKey(hkDoms);
377             hkDoms = NULL;
378         }
379     } else
380         DebugEvent("Not opening domain key for [%s]", effDomain);
381
382     /* Each individual can either be specified on the domain key, the domains key or in the
383        net provider key.  They fail over in that order.  If none is found, we just use the 
384        defaults. */
385
386     /* LogonOption */
387     LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
388
389     /* FailLoginsSilently */
390     dwSize = sizeof(dwDummy);
391     rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
392     if (rv != ERROR_SUCCESS)
393         LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
394     opt->failSilently = !!dwDummy;
395
396     /* Retry interval */
397     LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
398
399     /* Sleep interval */
400     LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
401
402     opt->logonScript = NULL;
403     opt->smbName = NULL;
404
405     if(!ISLOGONINTEGRATED(opt->LogonOption)) {
406         goto cleanup; /* no need to lookup the logon script */
407     }
408
409     /* come up with SMB username */
410     if(ISHIGHSECURITY(opt->LogonOption)) {
411         opt->smbName = malloc( MAXRANDOMNAMELEN );
412         GenRandomName(opt->smbName);
413     } else {
414         /* username and domain for logon session is not necessarily the same as
415            username and domain passed into network provider. */
416         PSECURITY_LOGON_SESSION_DATA plsd;
417         char lsaUsername[MAX_USERNAME_LENGTH];
418         char lsaDomain[MAX_DOMAIN_LENGTH];
419         size_t len, tlen;
420
421         LsaGetLogonSessionData(lpLogonId, &plsd);
422         
423         UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
424         UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
425
426         DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
427
428         if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
429             len = tlen;
430         else
431             goto bad_strings;
432
433         if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
434             len += tlen;
435         else
436             goto bad_strings;
437
438         len += 2;
439
440         opt->smbName = malloc(len);
441
442         StringCbCopy(opt->smbName, len, lsaDomain);
443         StringCbCat(opt->smbName, len, "\\");
444         StringCbCat(opt->smbName, len, lsaUsername);
445
446         strlwr(opt->smbName);
447
448       bad_strings:
449         LsaFreeReturnBuffer(plsd);
450     }
451
452     DebugEvent("Looking up logon script");
453     /* Logon script */
454     /* First find out where the key is */
455     hkTemp = NULL;
456     rv = ~ERROR_SUCCESS;
457     dwType = 0;
458     if(hkDom)
459         rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
460     if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
461         hkTemp = hkDom;
462         DebugEvent("Located logon script in hkDom");
463     }
464     else if(hkDoms)
465         rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
466     if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
467         hkTemp = hkDoms;
468         DebugEvent("Located logon script in hkDoms");
469     }
470     /* Note that the LogonScript in the NP key is only used if we are doing high security. */
471     else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
472         rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
473     if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
474         hkTemp = hkNp;
475         DebugEvent("Located logon script in hkNp");
476     }
477
478     if(hkTemp) {
479         WCHAR *regscript        = NULL;
480         WCHAR *regexscript      = NULL;
481         WCHAR *regexuscript     = NULL;
482         WCHAR *wuname           = NULL;
483         HRESULT hr;
484
485         size_t len;
486
487         StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
488         len ++;
489
490         wuname = malloc(len * sizeof(WCHAR));
491         MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,len*sizeof(WCHAR));
492
493         DebugEvent("Username is set for [%S]", wuname);
494
495         /* dwSize still has the size of the required buffer in bytes. */
496         regscript = malloc(dwSize);
497         rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
498         if(rv != ERROR_SUCCESS) {/* what the ..? */
499             DebugEvent("Can't look up logon script [%d]",rv);
500             goto doneLogonScript;
501         }
502
503         DebugEvent("Found logon script [%S]", regscript);
504
505         if(dwType == REG_EXPAND_SZ) {
506             DWORD dwReq;
507
508             dwSize += MAX_PATH * sizeof(WCHAR);  /* make room for environment expansion. */
509             regexscript = malloc(dwSize);
510             dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
511             free(regscript);
512             regscript = regexscript;
513             regexscript = NULL;
514             if(dwReq > (dwSize / sizeof(WCHAR))) {
515                 DebugEvent("Overflow while expanding environment strings.");
516                 goto doneLogonScript;
517             }
518         }
519
520         DebugEvent("After expanding env strings [%S]", regscript);
521
522         if(wcsstr(regscript, L"%s")) {
523             dwSize += len * sizeof(WCHAR); /* make room for username expansion */
524             regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
525             hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
526         } else {
527             regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
528             hr = StringCbCopyW(regexuscript, dwSize, regscript);
529         }
530
531         DebugEvent("After expanding username [%S]", regexuscript);
532
533         if(hr == S_OK)
534             opt->logonScript = regexuscript;
535         else
536             LocalFree(regexuscript);
537
538       doneLogonScript:
539         if(wuname) free(wuname);
540         if(regscript) free(regscript);
541         if(regexscript) free(regexscript);
542     }
543
544     DebugEvent("Looking up TheseCells");
545     /* Logon script */
546     /* First find out where the key is */
547     hkTemp = NULL;
548     rv = ~ERROR_SUCCESS;
549     dwType = 0;
550     if (hkDom)
551         rv = RegQueryValueEx(hkDom, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
552     if (rv == ERROR_SUCCESS && dwType == REG_MULTI_SZ) {
553         hkTemp = hkDom;
554         DebugEvent("Located TheseCells in hkDom");
555     } else if (hkDoms)
556         rv = RegQueryValueEx(hkDoms, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
557     if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
558         hkTemp = hkDoms;
559         DebugEvent("Located TheseCells in hkDoms");
560     } else if (hkNp)
561         rv = RegQueryValueEx(hkNp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
562     if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
563         hkTemp = hkNp;
564         DebugEvent("Located TheseCells in hkNp");
565     }
566
567     if (hkTemp) {
568         CHAR * thesecells;
569
570         /* dwSize still has the size of the required buffer in bytes. */
571         thesecells = malloc(dwSize);
572         rv = RegQueryValueEx(hkTemp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, (LPBYTE) thesecells, &dwSize);
573         if(rv != ERROR_SUCCESS) {/* what the ..? */
574             DebugEvent("Can't look up TheseCells [%d]",rv);
575             goto doneTheseCells;
576         }
577
578         DebugEvent("Found TheseCells [%s]", thesecells);
579         opt->theseCells = thesecells;
580
581       doneTheseCells:;
582     }
583
584   cleanup:
585     if(hkNp) RegCloseKey(hkNp);
586     if(hkDom) RegCloseKey(hkDom);
587     if(hkDoms) RegCloseKey(hkDoms);
588     if(hkParm) RegCloseKey(hkParm);
589 }       
590
591 #undef LOOKUPKEYCHAIN
592
593 /* Try to find out which cell the given path is in.  We must retain
594    the contents of *cell in case of failure. *cell is assumed to be
595    at least cellLen chars */
596 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
597     struct ViceIoctl blob;
598     char tcell[MAX_PATH];
599     DWORD code;
600
601     blob.in_size = 0;
602     blob.out_size = MAX_PATH;
603     blob.out = tcell;
604
605     code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
606
607     if(!code) {
608         strncpy(cell, tcell, cellLen);
609         cell[cellLen - 1] = '\0';
610     }
611     return code;
612 }       
613
614
615 static BOOL
616 WINAPI
617 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
618 {
619     CPINFO CodePageInfo;
620
621     GetCPInfo(CP_ACP, &CodePageInfo);
622
623     if (CodePageInfo.MaxCharSize > 1)
624         // Only supporting non-Unicode strings
625         return FALSE;
626     
627     if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
628     {
629         // Looks like unicode, better translate it
630         // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
631         WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
632                             lpszOutputString, nOutStringLen-1, NULL, NULL);
633         lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
634         return TRUE;
635     }
636     else
637         lpszOutputString[0] = '\0';
638     return FALSE;
639 }  // UnicodeStringToANSI
640
641 DWORD APIENTRY NPLogonNotify(
642         PLUID lpLogonId,
643         LPCWSTR lpAuthentInfoType,
644         LPVOID lpAuthentInfo,
645         LPCWSTR lpPreviousAuthentInfoType,
646         LPVOID lpPreviousAuthentInfo,
647         LPWSTR lpStationName,
648         LPVOID StationHandle,
649         LPWSTR *lpLogonScript)
650 {
651     char uname[MAX_USERNAME_LENGTH]="";
652     char password[MAX_PASSWORD_LENGTH]="";
653     char logonDomain[MAX_DOMAIN_LENGTH]="";
654     char cell[256]="<non-integrated logon>";
655     char homePath[MAX_PATH]="";
656     char szLogonId[128] = "";
657
658     MSV1_0_INTERACTIVE_LOGON *IL;
659
660     DWORD code, code2;
661
662     int pw_exp;
663     char *reason;
664     char *ctemp;
665
666     BOOLEAN interactive;
667     BOOLEAN flag;
668     DWORD LSPtype, LSPsize;
669     HKEY NPKey;
670
671     HWND hwndOwner = (HWND)StationHandle;
672
673     BOOLEAN afsWillAutoStart;
674
675     BOOLEAN lowercased_name = TRUE;
676
677     LogonOptions_t opt; /* domain specific logon options */
678     int retryInterval;
679     int sleepInterval;
680
681     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
682                          0, KEY_QUERY_VALUE, &NPKey);
683     LSPsize=sizeof(TraceOption);
684     RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
685                      &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
686
687     RegCloseKey (NPKey);
688
689     DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart);
690
691     /* Make sure the AFS Libraries are initialized */
692     AfsLogonInit();
693
694     /* Initialize Logon Script to none */
695     *lpLogonScript=NULL;
696     
697     /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for
698      * our purposes */
699
700     if ( wcscmp(lpAuthentInfoType,L"MSV1_0:Interactive") && 
701          wcscmp(lpAuthentInfoType,L"Kerberos:Interactive") )
702     {
703         DebugEvent("Unsupported Authentication Info Type: %S",
704                    lpAuthentInfoType);
705         return 0;
706     }
707
708     IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
709
710     /* Are we interactive? */
711     interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
712
713     /* Convert from Unicode to ANSI */
714
715     /*TODO: Use SecureZeroMemory to erase passwords */
716     UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
717     UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
718     UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
719
720     /* Make sure AD-DOMANS sent from login that is sent to us is striped */
721     ctemp = strchr(uname, '@');
722     if (ctemp) *ctemp = 0;
723
724     /* is the name all lowercase? */
725     for ( ctemp = uname; *ctemp ; ctemp++) {
726         if ( !islower(*ctemp) ) {
727             lowercased_name = FALSE;
728             break;
729         }
730     }
731
732     /*
733      * Get Logon options
734      */
735
736     GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
737     retryInterval = opt.retryInterval;
738     sleepInterval = opt.sleepInterval;
739     *lpLogonScript = opt.logonScript;
740
741     if (retryInterval < sleepInterval)
742         sleepInterval = retryInterval;
743
744     DebugEvent("Got logon script: %S",opt.logonScript);
745
746     afsWillAutoStart = AFSWillAutoStart();
747
748     DebugEvent("LogonOption[%x], Service AutoStart[%d]",
749                 opt.LogonOption,afsWillAutoStart);
750     
751     /* Check for zero length password if integrated logon*/
752     if ( ISLOGONINTEGRATED(opt.LogonOption) )  {
753         if ( password[0] == 0 ) {
754             DebugEvent("Password is the empty string");
755             code = GT_PW_NULL;
756             reason = "zero length password is illegal";
757             code=0;
758         }       
759
760         /* Get cell name if doing integrated logon.  
761            We might overwrite this if we are logging into an AD realm and we find out that
762            the user's home dir is in some other cell. */
763         DebugEvent("About to call cm_GetRootCellName(%s)",cell);
764         code = cm_GetRootCellName(cell);
765         if (code < 0) { 
766             DebugEvent("Unable to obtain Root Cell");
767             code = KTC_NOCELL;
768             reason = "unknown cell";
769             code=0;
770         } else {
771             DebugEvent("Cell is %s",cell);
772         }       
773
774         /* We get the user's home directory path, if applicable, though we can't lookup the
775            cell right away because the client service may not have started yet. This call
776            also sets the AD_REALM flag in opt.flags if applicable. */
777         if (ISREMOTE(opt.flags)) {
778             DebugEvent("Is Remote");
779             GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
780         }       
781     }
782
783     /* loop until AFS is started. */
784     while (IsServiceRunning() || IsServiceStartPending()) {
785         DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
786                     opt.LogonOption,afsWillAutoStart);
787
788         if (ISADREALM(opt.flags)) {
789             code = GetFileCellName(homePath,cell,256);
790             if (!code) {
791                 DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
792             }
793             /* Don't bail out if GetFileCellName failed.
794              * The home dir may not be in AFS after all. 
795              */
796         } else
797             code=0;
798                 
799         /* if Integrated Logon  */
800         if (ISLOGONINTEGRATED(opt.LogonOption))
801         {                       
802             if ( KFW_is_available() ) {
803                 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
804                 DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",uname,opt.smbName,cell,code);
805                 if (code == 0 && opt.theseCells) { 
806                     char * principal, *p;
807
808                     principal = (char *)malloc(strlen(uname) + strlen(cell) + 2);
809                     if ( principal ) {
810                         strcpy(principal, uname);
811                         p = principal + strlen(uname);
812                         *p++ = '@';
813                         strcpy(p, cell);
814                         for ( ;*p; p++) {
815                             *p = toupper(*p);
816                         }
817
818                         p = opt.theseCells;
819                         while ( *p ) {
820                             code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
821                             DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
822                                         principal,opt.smbName,p,code2);
823                             p += strlen(p) + 1;
824                         }
825                         
826                         free(principal);
827                     }
828                 }
829             } else {
830                 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
831                                                     uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
832                                                     &reason);
833                 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s]",
834                             code,uname,cell);
835             }       
836             if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
837                 for ( ctemp = uname; *ctemp ; ctemp++) {
838                     *ctemp = tolower(*ctemp);
839                 }
840                 lowercased_name = TRUE;
841                 goto sleeping;
842             }
843
844             /* is service started yet?*/
845
846             /* If we've failed because the client isn't running yet and the
847             * client is set to autostart (and therefore it makes sense for
848             * us to wait for it to start) then sleep a while and try again. 
849             * If the error was something else, then give up. */
850             if (code != KTC_NOCM && code != KTC_NOCMRPC)
851                 break;
852         }
853         else {  
854             /*JUST check to see if its running*/
855             if (IsServiceRunning())
856                 break;
857             if (!IsServiceStartPending()) {
858                 code = KTC_NOCMRPC;
859                 reason = "AFS Service start failed";
860                 break;
861             }
862         }
863
864         /* If the retry interval has expired and we still aren't
865          * logged in, then just give up if we are not in interactive
866          * mode or the failSilently flag is set, otherwise let the
867          * user know we failed and give them a chance to try again. */
868         if (retryInterval <= 0) {
869             reason = "AFS not running";
870             if (!interactive || opt.failSilently)
871                 break;
872             flag = MessageBox(hwndOwner,
873                                "AFS is still starting.  Retry?",
874                                "AFS Logon",
875                                MB_ICONQUESTION | MB_RETRYCANCEL);
876             if (flag == IDCANCEL)
877                 break;
878
879             /* Wait just a little while and try again */
880             retryInterval = opt.retryInterval;
881         }
882
883       sleeping:
884         Sleep(sleepInterval * 1000);
885         retryInterval -= sleepInterval;
886     }
887
888     DebugEvent("while loop exited");
889     /* remove any kerberos 5 tickets currently held by the SYSTEM account
890      * for this user 
891      */
892     if ( KFW_is_available() ) {
893         sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
894         KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
895
896         KFW_AFS_destroy_tickets_for_principal(uname);
897     }
898
899     if (code) {
900         char msg[128];
901         HANDLE h;
902         char *ptbuf[1];
903
904         StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
905
906         if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
907             MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
908
909         h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
910         ptbuf[0] = msg;
911         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
912                      1, 0, ptbuf, NULL);
913         DeregisterEventSource(h);
914             
915         code = MapAuthError(code);
916         SetLastError(code);
917
918         if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
919         {
920             if (*lpLogonScript)
921                 LocalFree(*lpLogonScript);
922             *lpLogonScript = NULL;
923             if (!afsWillAutoStart)      // its not running, so if not autostart or integrated logon then just skip
924                 code = 0;
925         }
926     }
927
928     if (opt.theseCells) free(opt.theseCells);
929     if (opt.smbName) free(opt.smbName);
930
931     DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
932     return code;
933 }       
934
935 DWORD APIENTRY NPPasswordChangeNotify(
936         LPCWSTR lpAuthentInfoType,
937         LPVOID lpAuthentInfo,
938         LPCWSTR lpPreviousAuthentInfoType,
939         LPVOID lpPreviousAuthentInfo,
940         LPWSTR lpStationName,
941         LPVOID StationHandle,
942         DWORD dwChangeInfo)
943 {
944     /* Make sure the AFS Libraries are initialized */
945     AfsLogonInit();
946
947     DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
948     return 0;
949 }
950
951 #include <userenv.h>
952 #include <Winwlx.h>
953 #include <afs/vice.h>
954 #include <afs/fs_utils.h>
955
956 BOOL IsPathInAfs(const CHAR *strPath)
957 {
958     char space[2048];
959     struct ViceIoctl blob;
960     int code;
961
962     blob.in_size = 0;
963     blob.out_size = 2048;
964     blob.out = space;
965
966     code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
967     if (code)
968         return FALSE;
969     return TRUE;
970 }
971
972 #ifdef COMMENT
973 typedef struct _WLX_NOTIFICATION_INFO {  
974     ULONG Size;  
975     ULONG Flags;  
976     PWSTR UserName;  
977     PWSTR Domain;  
978     PWSTR WindowStation;  
979     HANDLE hToken;  
980     HDESK hDesktop;  
981     PFNMSGECALLBACK pStatusCallback;
982 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
983 #endif
984
985 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
986 {
987     DWORD LSPtype, LSPsize;
988     HKEY NPKey;
989
990     /* Make sure the AFS Libraries are initialized */
991     AfsLogonInit();
992
993     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
994                         0, KEY_QUERY_VALUE, &NPKey);
995     LSPsize=sizeof(TraceOption);
996     RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
997                      &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
998
999     RegCloseKey (NPKey);
1000     DebugEvent0("AFS_Startup_Event");
1001 }
1002
1003 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
1004 {
1005     DWORD code;
1006     TCHAR profileDir[1024] = TEXT("");
1007     DWORD  len = 1024;
1008     PTOKEN_USER  tokenUser = NULL;
1009     DWORD  retLen;
1010     DWORD LSPtype, LSPsize;
1011     HKEY NPKey;
1012     DWORD LogoffPreserveTokens = 0;
1013
1014     /* Make sure the AFS Libraries are initialized */
1015     AfsLogonInit();
1016
1017     DebugEvent0("AFS_Logoff_Event - Start");
1018
1019     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1020                          0, KEY_QUERY_VALUE, &NPKey);
1021     LSPsize=sizeof(LogoffPreserveTokens);
1022     RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
1023                      &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
1024     RegCloseKey (NPKey);
1025
1026     if (LogoffPreserveTokens) {
1027         if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1028         {
1029             if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1030                 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1031
1032                 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1033                 {
1034                     DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1035                 }
1036             }
1037         }
1038
1039         /* We can't use pInfo->Domain for the domain since in the cross realm case 
1040          * this is source domain and not the destination domain.
1041          */
1042         if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1043             WCHAR Domain[64]=L"";
1044             GetLocalShortDomain(Domain, sizeof(Domain));
1045             if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1046                 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1047                     GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1048             }
1049         }
1050
1051         if (strlen(profileDir)) {
1052             DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1053             if (!IsPathInAfs(profileDir)) {
1054                 if (code = ktc_ForgetAllTokens())
1055                     DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1056                 else
1057                     DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1058             } else {
1059                 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1060             }
1061         } else {
1062             DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1063         }
1064
1065         if ( tokenUser )
1066             LocalFree(tokenUser);
1067     }
1068
1069     DebugEvent0("AFS_Logoff_Event - End");
1070 }   
1071
1072 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1073 {
1074     TCHAR profileDir[1024] = TEXT("");
1075     DWORD  len = 1024;
1076     PTOKEN_USER  tokenUser = NULL;
1077     DWORD  retLen;
1078     WCHAR szUserW[128] = L"";
1079     char  szUserA[128] = "";
1080     char  szClient[MAX_PATH];
1081     char szPath[MAX_PATH] = "";
1082     NETRESOURCE nr;
1083     DWORD res;
1084     DWORD dwSize;
1085
1086     /* Make sure the AFS Libraries are initialized */
1087     AfsLogonInit();
1088
1089     DebugEvent0("AFS_Logon_Event - Start");
1090
1091     DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1092
1093     if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1094     {
1095         if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1096             tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1097
1098             if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1099             {
1100                 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1101             }
1102         }
1103     }
1104
1105     /* We can't use pInfo->Domain for the domain since in the cross realm case 
1106      * this is source domain and not the destination domain.
1107      */
1108     if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1109         WCHAR Domain[64]=L"";
1110         GetLocalShortDomain(Domain, sizeof(Domain));
1111         if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1112             if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1113                 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1114         }
1115     }
1116     
1117     if (strlen(profileDir)) {
1118         DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1119     } else {
1120         DebugEvent0("AFS_Logon_Event - Unable to load profile");
1121     }
1122
1123     dwSize = sizeof(szUserA);
1124     if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1125         StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1126         WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1127     }
1128
1129     if (szUserA[0])
1130     {
1131         lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1132         StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1133
1134         DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1135
1136         memset (&nr, 0x00, sizeof(NETRESOURCE));
1137         nr.dwType=RESOURCETYPE_DISK;
1138         nr.lpLocalName=0;
1139         nr.lpRemoteName=szPath;
1140         res = WNetAddConnection2(&nr,NULL,szUserA,0);
1141         if (res)
1142             DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1143                         szPath, szUserA,res);
1144         else
1145             DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1146     } else 
1147         DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1148
1149     if ( tokenUser )
1150         LocalFree(tokenUser);
1151
1152     DebugEvent0("AFS_Logon_Event - End");
1153 }
1154
1155 static BOOL
1156 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1157 {
1158     NTSTATUS Status = 0;
1159     HANDLE  TokenHandle;
1160     TOKEN_STATISTICS Stats;
1161     DWORD   ReqLen;
1162     BOOL    Success;
1163
1164     if (!ppSessionData)
1165         return FALSE;
1166     *ppSessionData = NULL;
1167
1168 #if 0
1169     Success = OpenProcessToken( HANDLE GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1170     if ( !Success )
1171         return FALSE;
1172 #endif
1173
1174     Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1175 #if 0
1176     CloseHandle( TokenHandle );
1177 #endif
1178     if ( !Success )
1179         return FALSE;
1180
1181     Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1182     if ( FAILED(Status) || !ppSessionData )
1183         return FALSE;
1184
1185     return TRUE;
1186 }
1187
1188 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1189 {
1190     DWORD code;
1191
1192     WCHAR szUserW[128] = L"";
1193     char  szUserA[128] = "";
1194     char  szClient[MAX_PATH];
1195     char szPath[MAX_PATH] = "";
1196     char szLogonId[128] = "";
1197     NETRESOURCE nr;
1198     DWORD res;
1199     DWORD gle;
1200     DWORD dwSize;
1201     DWORD dwDisp;
1202     DWORD dwType;
1203     DWORD count;
1204     VOID * ticketData;
1205     char filename[256];
1206     char commandline[512];
1207     STARTUPINFO startupinfo;
1208     PROCESS_INFORMATION procinfo;
1209
1210     LUID LogonId = {0, 0};
1211     PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1212
1213     HKEY hKey1 = NULL, hKey2 = NULL;
1214
1215     /* Make sure the KFW Libraries are initialized */
1216     AfsLogonInit();
1217
1218     DebugEvent0("KFW_Logon_Event - Start");
1219
1220     GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1221
1222     if ( pLogonSessionData ) {
1223         LogonId = pLogonSessionData->LogonId;
1224         DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1225
1226         sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1227         LsaFreeReturnBuffer( pLogonSessionData );
1228     } else {
1229         DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1230         return;
1231     }
1232
1233     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1234     if ( count > sizeof(filename) || count == 0 ) {
1235         GetWindowsDirectory(filename, sizeof(filename));
1236     }
1237
1238     if ( strlen(filename) + strlen(szLogonId) + 2 <= sizeof(filename) ) {
1239         strcat(filename, "\\");
1240         strcat(filename, szLogonId);    
1241
1242         sprintf(commandline, "afscpcc.exe \"%s\"", filename);
1243
1244         GetStartupInfo(&startupinfo);
1245         if (CreateProcessAsUser( pInfo->hToken,
1246                              "afscpcc.exe",
1247                              commandline,
1248                              NULL,
1249                              NULL,
1250                              FALSE,
1251                              CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1252                              NULL,
1253                              NULL,
1254                              &startupinfo,
1255                              &procinfo)) 
1256         {
1257             WaitForSingleObject(procinfo.hProcess, 30000);
1258
1259             CloseHandle(procinfo.hThread);
1260             CloseHandle(procinfo.hProcess);
1261         }
1262     }
1263
1264     DeleteFile(filename);
1265
1266     DebugEvent0("KFW_Logon_Event - End");
1267 }
1268