windows-logon-20050613
[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
1011     /* Make sure the AFS Libraries are initialized */
1012     AfsLogonInit();
1013
1014     DebugEvent0("AFS_Logoff_Event - Start");
1015
1016     if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1017     {
1018         if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1019             tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1020
1021             if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1022             {
1023                 DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1024             }
1025         }
1026     }
1027
1028     /* We can't use pInfo->Domain for the domain since in the cross realm case 
1029      * this is source domain and not the destination domain.
1030      */
1031     if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1032         WCHAR Domain[64]=L"";
1033         GetLocalShortDomain(Domain, sizeof(Domain));
1034         if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1035             if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1036                 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1037         }
1038     }
1039     
1040     if (strlen(profileDir)) {
1041         DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1042         if (!IsPathInAfs(profileDir)) {
1043             if (code = ktc_ForgetAllTokens())
1044                 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1045             else
1046                 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1047         } else {
1048             DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1049         }
1050     } else {
1051         DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1052     }
1053
1054     if ( tokenUser )
1055         LocalFree(tokenUser);
1056
1057     DebugEvent0("AFS_Logoff_Event - End");
1058 }   
1059
1060 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1061 {
1062     TCHAR profileDir[1024] = TEXT("");
1063     DWORD  len = 1024;
1064     PTOKEN_USER  tokenUser = NULL;
1065     DWORD  retLen;
1066     WCHAR szUserW[128] = L"";
1067     char  szUserA[128] = "";
1068     char  szClient[MAX_PATH];
1069     char szPath[MAX_PATH] = "";
1070     NETRESOURCE nr;
1071     DWORD res;
1072     DWORD dwSize;
1073
1074     /* Make sure the AFS Libraries are initialized */
1075     AfsLogonInit();
1076
1077     DebugEvent0("AFS_Logon_Event - Start");
1078
1079     DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1080
1081     if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1082     {
1083         if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1084             tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1085
1086             if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1087             {
1088                 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1089             }
1090         }
1091     }
1092
1093     /* We can't use pInfo->Domain for the domain since in the cross realm case 
1094      * this is source domain and not the destination domain.
1095      */
1096     if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1097         WCHAR Domain[64]=L"";
1098         GetLocalShortDomain(Domain, sizeof(Domain));
1099         if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1100             if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1101                 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1102         }
1103     }
1104     
1105     if (strlen(profileDir)) {
1106         DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1107     } else {
1108         DebugEvent0("AFS_Logon_Event - Unable to load profile");
1109     }
1110
1111     dwSize = sizeof(szUserA);
1112     if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1113         StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1114         WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1115     }
1116
1117     if (szUserA[0])
1118     {
1119         lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1120         StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1121
1122         DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1123
1124         memset (&nr, 0x00, sizeof(NETRESOURCE));
1125         nr.dwType=RESOURCETYPE_DISK;
1126         nr.lpLocalName=0;
1127         nr.lpRemoteName=szPath;
1128         res = WNetAddConnection2(&nr,NULL,szUserA,0);
1129         if (res)
1130             DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1131                         szPath, szUserA,res);
1132         else
1133             DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1134     } else 
1135         DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1136
1137     if ( tokenUser )
1138         LocalFree(tokenUser);
1139
1140     DebugEvent0("AFS_Logon_Event - End");
1141 }
1142
1143 static BOOL
1144 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1145 {
1146     NTSTATUS Status = 0;
1147     HANDLE  TokenHandle;
1148     TOKEN_STATISTICS Stats;
1149     DWORD   ReqLen;
1150     BOOL    Success;
1151
1152     if (!ppSessionData)
1153         return FALSE;
1154     *ppSessionData = NULL;
1155
1156 #if 0
1157     Success = OpenProcessToken( HANDLE GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1158     if ( !Success )
1159         return FALSE;
1160 #endif
1161
1162     Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1163 #if 0
1164     CloseHandle( TokenHandle );
1165 #endif
1166     if ( !Success )
1167         return FALSE;
1168
1169     Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1170     if ( FAILED(Status) || !ppSessionData )
1171         return FALSE;
1172
1173     return TRUE;
1174 }
1175
1176 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1177 {
1178     DWORD code;
1179
1180     WCHAR szUserW[128] = L"";
1181     char  szUserA[128] = "";
1182     char  szClient[MAX_PATH];
1183     char szPath[MAX_PATH] = "";
1184     char szLogonId[128] = "";
1185     NETRESOURCE nr;
1186     DWORD res;
1187     DWORD gle;
1188     DWORD dwSize;
1189     DWORD dwDisp;
1190     DWORD dwType;
1191     DWORD count;
1192     VOID * ticketData;
1193     char filename[256];
1194     char commandline[512];
1195     STARTUPINFO startupinfo;
1196     PROCESS_INFORMATION procinfo;
1197
1198     LUID LogonId = {0, 0};
1199     PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1200
1201     HKEY hKey1 = NULL, hKey2 = NULL;
1202
1203     /* Make sure the KFW Libraries are initialized */
1204     AfsLogonInit();
1205
1206     DebugEvent0("KFW_Logon_Event - Start");
1207
1208     GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1209
1210     if ( pLogonSessionData ) {
1211         LogonId = pLogonSessionData->LogonId;
1212         DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1213
1214         sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1215         LsaFreeReturnBuffer( pLogonSessionData );
1216     } else {
1217         DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1218         return;
1219     }
1220
1221     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1222     if ( count > sizeof(filename) || count == 0 ) {
1223         GetWindowsDirectory(filename, sizeof(filename));
1224     }
1225
1226     if ( strlen(filename) + strlen(szLogonId) + 2 <= sizeof(filename) ) {
1227         strcat(filename, "\\");
1228         strcat(filename, szLogonId);    
1229
1230         sprintf(commandline, "afscpcc.exe \"%s\"", filename);
1231
1232         GetStartupInfo(&startupinfo);
1233         if (CreateProcessAsUser( pInfo->hToken,
1234                              "afscpcc.exe",
1235                              commandline,
1236                              NULL,
1237                              NULL,
1238                              FALSE,
1239                              CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1240                              NULL,
1241                              NULL,
1242                              &startupinfo,
1243                              &procinfo)) 
1244         {
1245             WaitForSingleObject(procinfo.hProcess, 30000);
1246
1247             CloseHandle(procinfo.hThread);
1248             CloseHandle(procinfo.hProcess);
1249         }
1250     }
1251
1252     DeleteFile(filename);
1253
1254     DebugEvent0("KFW_Logon_Event - End");
1255 }
1256