windows-afslogon-20060204
[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 if (lpLogonId) {
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     } else {
451         size_t len;
452
453         DebugEvent("No LUID given. Constructing username using [%s] and [%s]",
454                    username, domain);
455  
456         len = strlen(username) + strlen(domain) + 2;
457
458         opt->smbName = malloc(len);
459
460         StringCbCopy(opt->smbName, len, username);
461         StringCbCat(opt->smbName, len, "\\");
462         StringCbCat(opt->smbName, len, domain);
463
464         strlwr(opt->smbName);
465     }
466
467     DebugEvent("Looking up logon script");
468     /* Logon script */
469     /* First find out where the key is */
470     hkTemp = NULL;
471     rv = ~ERROR_SUCCESS;
472     dwType = 0;
473     if(hkDom)
474         rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
475     if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
476         hkTemp = hkDom;
477         DebugEvent("Located logon script in hkDom");
478     }
479     else if(hkDoms)
480         rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
481     if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
482         hkTemp = hkDoms;
483         DebugEvent("Located logon script in hkDoms");
484     }
485     /* Note that the LogonScript in the NP key is only used if we are doing high security. */
486     else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
487         rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
488     if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
489         hkTemp = hkNp;
490         DebugEvent("Located logon script in hkNp");
491     }
492
493     if(hkTemp) {
494         WCHAR *regscript        = NULL;
495         WCHAR *regexscript      = NULL;
496         WCHAR *regexuscript     = NULL;
497         WCHAR *wuname           = NULL;
498         HRESULT hr;
499
500         size_t len;
501
502         StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
503         len ++;
504
505         wuname = malloc(len * sizeof(WCHAR));
506         MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,(int)(len*sizeof(WCHAR)));
507
508         DebugEvent("Username is set for [%S]", wuname);
509
510         /* dwSize still has the size of the required buffer in bytes. */
511         regscript = malloc(dwSize);
512         rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
513         if(rv != ERROR_SUCCESS) {/* what the ..? */
514             DebugEvent("Can't look up logon script [%d]",rv);
515             goto doneLogonScript;
516         }
517
518         DebugEvent("Found logon script [%S]", regscript);
519
520         if(dwType == REG_EXPAND_SZ) {
521             DWORD dwReq;
522
523             dwSize += MAX_PATH * sizeof(WCHAR);  /* make room for environment expansion. */
524             regexscript = malloc(dwSize);
525             dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
526             free(regscript);
527             regscript = regexscript;
528             regexscript = NULL;
529             if(dwReq > (dwSize / sizeof(WCHAR))) {
530                 DebugEvent("Overflow while expanding environment strings.");
531                 goto doneLogonScript;
532             }
533         }
534
535         DebugEvent("After expanding env strings [%S]", regscript);
536
537         if(wcsstr(regscript, L"%s")) {
538             dwSize += (DWORD)(len * sizeof(WCHAR)); /* make room for username expansion */
539             regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
540             hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
541         } else {
542             regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
543             hr = StringCbCopyW(regexuscript, dwSize, regscript);
544         }
545
546         DebugEvent("After expanding username [%S]", regexuscript);
547
548         if(hr == S_OK)
549             opt->logonScript = regexuscript;
550         else
551             LocalFree(regexuscript);
552
553       doneLogonScript:
554         if(wuname) free(wuname);
555         if(regscript) free(regscript);
556         if(regexscript) free(regexscript);
557     }
558
559     DebugEvent("Looking up TheseCells");
560     /* Logon script */
561     /* First find out where the key is */
562     hkTemp = NULL;
563     rv = ~ERROR_SUCCESS;
564     dwType = 0;
565     if (hkDom)
566         rv = RegQueryValueEx(hkDom, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
567     if (rv == ERROR_SUCCESS && dwType == REG_MULTI_SZ) {
568         hkTemp = hkDom;
569         DebugEvent("Located TheseCells in hkDom");
570     } else if (hkDoms)
571         rv = RegQueryValueEx(hkDoms, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
572     if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
573         hkTemp = hkDoms;
574         DebugEvent("Located TheseCells in hkDoms");
575     } else if (hkNp)
576         rv = RegQueryValueEx(hkNp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
577     if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
578         hkTemp = hkNp;
579         DebugEvent("Located TheseCells in hkNp");
580     }
581
582     if (hkTemp) {
583         CHAR * thesecells;
584
585         /* dwSize still has the size of the required buffer in bytes. */
586         thesecells = malloc(dwSize);
587         rv = RegQueryValueEx(hkTemp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, (LPBYTE) thesecells, &dwSize);
588         if(rv != ERROR_SUCCESS) {/* what the ..? */
589             DebugEvent("Can't look up TheseCells [%d]",rv);
590             goto doneTheseCells;
591         }
592
593         DebugEvent("Found TheseCells [%s]", thesecells);
594         opt->theseCells = thesecells;
595
596       doneTheseCells:
597         ;
598     }
599
600   cleanup:
601     if(hkNp) RegCloseKey(hkNp);
602     if(hkDom) RegCloseKey(hkDom);
603     if(hkDoms) RegCloseKey(hkDoms);
604     if(hkParm) RegCloseKey(hkParm);
605 }       
606
607 #undef LOOKUPKEYCHAIN
608
609 /* Try to find out which cell the given path is in.  We must retain
610    the contents of *cell in case of failure. *cell is assumed to be
611    at least cellLen chars */
612 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
613     struct ViceIoctl blob;
614     char tcell[MAX_PATH];
615     DWORD code;
616
617     blob.in_size = 0;
618     blob.out_size = MAX_PATH;
619     blob.out = tcell;
620
621     code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
622
623     if(!code) {
624         strncpy(cell, tcell, cellLen);
625         cell[cellLen - 1] = '\0';
626     }
627     return code;
628 }       
629
630
631 static BOOL
632 WINAPI
633 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
634 {
635     CPINFO CodePageInfo;
636
637     GetCPInfo(CP_ACP, &CodePageInfo);
638
639     if (CodePageInfo.MaxCharSize > 1)
640         // Only supporting non-Unicode strings
641         return FALSE;
642     
643     if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
644     {
645         // Looks like unicode, better translate it
646         // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
647         WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
648                             lpszOutputString, nOutStringLen-1, NULL, NULL);
649         lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
650         return TRUE;
651     }
652     else
653         lpszOutputString[0] = '\0';
654     return FALSE;
655 }  // UnicodeStringToANSI
656
657 DWORD APIENTRY NPLogonNotify(
658         PLUID lpLogonId,
659         LPCWSTR lpAuthentInfoType,
660         LPVOID lpAuthentInfo,
661         LPCWSTR lpPreviousAuthentInfoType,
662         LPVOID lpPreviousAuthentInfo,
663         LPWSTR lpStationName,
664         LPVOID StationHandle,
665         LPWSTR *lpLogonScript)
666 {
667     char uname[MAX_USERNAME_LENGTH]="";
668     char password[MAX_PASSWORD_LENGTH]="";
669     char logonDomain[MAX_DOMAIN_LENGTH]="";
670     char cell[256]="<non-integrated logon>";
671     char homePath[MAX_PATH]="";
672     char szLogonId[128] = "";
673
674     MSV1_0_INTERACTIVE_LOGON *IL;
675
676     DWORD code = 0, code2;
677
678     int pw_exp;
679     char *reason;
680     char *ctemp;
681
682     BOOLEAN interactive;
683     BOOLEAN flag;
684     DWORD LSPtype, LSPsize;
685     HKEY NPKey;
686
687     HWND hwndOwner = (HWND)StationHandle;
688
689     BOOLEAN afsWillAutoStart;
690
691     BOOLEAN lowercased_name = TRUE;
692
693     LogonOptions_t opt; /* domain specific logon options */
694     int retryInterval;
695     int sleepInterval;
696
697     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
698                          0, KEY_QUERY_VALUE, &NPKey);
699     LSPsize=sizeof(TraceOption);
700     RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
701                      &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
702
703     RegCloseKey (NPKey);
704
705     DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart);
706
707     /* Make sure the AFS Libraries are initialized */
708     AfsLogonInit();
709
710     /* Initialize Logon Script to none */
711     *lpLogonScript=NULL;
712     
713     /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for
714      * our purposes */
715
716     if ( wcscmp(lpAuthentInfoType,L"MSV1_0:Interactive") && 
717          wcscmp(lpAuthentInfoType,L"Kerberos:Interactive") )
718     {
719         DebugEvent("Unsupported Authentication Info Type: %S",
720                    lpAuthentInfoType);
721         return 0;
722     }
723
724     IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
725
726     /* Are we interactive? */
727     interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
728
729     /* Convert from Unicode to ANSI */
730
731     /*TODO: Use SecureZeroMemory to erase passwords */
732     UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
733     UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
734     UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
735
736     /* Make sure AD-DOMANS sent from login that is sent to us is striped */
737     ctemp = strchr(uname, '@');
738     if (ctemp) *ctemp = 0;
739
740     /* is the name all lowercase? */
741     for ( ctemp = uname; *ctemp ; ctemp++) {
742         if ( !islower(*ctemp) ) {
743             lowercased_name = FALSE;
744             break;
745         }
746     }
747
748     /*
749      * Get Logon options
750      */
751
752     GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
753     retryInterval = opt.retryInterval;
754     sleepInterval = opt.sleepInterval;
755     *lpLogonScript = opt.logonScript;
756
757     if (retryInterval < sleepInterval)
758         sleepInterval = retryInterval;
759
760     DebugEvent("Got logon script: %S",opt.logonScript);
761
762     afsWillAutoStart = AFSWillAutoStart();
763
764     DebugEvent("LogonOption[%x], Service AutoStart[%d]",
765                 opt.LogonOption,afsWillAutoStart);
766     
767     /* Check for zero length password if integrated logon*/
768     if ( ISLOGONINTEGRATED(opt.LogonOption) )  {
769         if ( password[0] == 0 ) {
770             DebugEvent("Password is the empty string");
771             code = GT_PW_NULL;
772             reason = "zero length password is illegal";
773             code=0;
774         }
775
776         /* Get cell name if doing integrated logon.  
777            We might overwrite this if we are logging into an AD realm and we find out that
778            the user's home dir is in some other cell. */
779         DebugEvent("About to call cm_GetRootCellName(%s)",cell);
780         code = cm_GetRootCellName(cell);
781         if (code < 0) { 
782             DebugEvent("Unable to obtain Root Cell");
783             code = KTC_NOCELL;
784             reason = "unknown cell";
785             code=0;
786         } else {
787             DebugEvent("Cell is %s",cell);
788         }       
789
790         /* We get the user's home directory path, if applicable, though we can't lookup the
791            cell right away because the client service may not have started yet. This call
792            also sets the AD_REALM flag in opt.flags if applicable. */
793         if (ISREMOTE(opt.flags)) {
794             DebugEvent("Is Remote");
795             GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
796         }
797     }
798
799     /* loop until AFS is started. */
800     if (afsWillAutoStart) {
801         while (IsServiceRunning() || IsServiceStartPending()) {
802             DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
803                         opt.LogonOption,afsWillAutoStart);
804
805             if (ISADREALM(opt.flags)) {
806                 code = GetFileCellName(homePath,cell,256);
807                 if (!code) {
808                     DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
809                 }
810                 /* Don't bail out if GetFileCellName failed.
811                  * The home dir may not be in AFS after all. 
812                  */
813             } else
814                 code=0;
815                 
816             /* if Integrated Logon  */
817             if (ISLOGONINTEGRATED(opt.LogonOption))
818             {                   
819                 if ( KFW_is_available() ) {
820                     code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
821                     DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
822                                 uname,opt.smbName,cell,code);
823                     if (code == 0 && opt.theseCells) { 
824                         char * principal, *p;
825                         size_t len, tlen;
826
827                         StringCchLength(cell, MAX_DOMAIN_LENGTH, &tlen);
828                         len = tlen;
829                         StringCchLength(uname, MAX_USERNAME_LENGTH, &tlen);
830                         len += tlen + 2;
831
832                         /* tlen is now the length of uname in characters */
833                         principal = (char *)malloc(len * sizeof(char));
834                         if ( principal ) {
835                             StringCchCopy(principal, len, uname);
836                             p = principal + tlen;
837                             *p++ = '@';
838                             StringCchCopy(p, len - tlen - 1, cell);
839                             for ( ;*p; p++) {
840                                 *p = toupper(*p);
841                             }
842
843                             p = opt.theseCells;
844                             while ( *p ) {
845                                 code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
846                                 DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
847                                             principal,opt.smbName,p,code2);
848                                 p += strlen(p) + 1;
849                             }
850                             free(principal);
851                         }
852                     }
853                 } else {
854                     code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
855                                                         uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
856                                                         &reason);
857                     DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2 Code[%x] uname[%s] smbname=[%s] Cell[%s] PwExp=[%d] Reason=[%s]",
858                                 code,uname,opt.smbName,cell,pw_exp,reason?reason:"");
859                 }       
860                 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
861                     for ( ctemp = uname; *ctemp ; ctemp++) {
862                         *ctemp = tolower(*ctemp);
863                     }
864                     lowercased_name = TRUE;
865                     goto sleeping;
866                 }
867
868                 /* is service started yet?*/
869
870                 /* If we've failed because the client isn't running yet and the
871                  * client is set to autostart (and therefore it makes sense for
872                  * us to wait for it to start) then sleep a while and try again. 
873                  * If the error was something else, then give up. */
874                 if (code != KTC_NOCM && code != KTC_NOCMRPC)
875                     break;
876             }
877             else {  
878                 /*JUST check to see if its running*/
879                 if (IsServiceRunning())
880                     break;
881                 if (!IsServiceStartPending()) {
882                     code = KTC_NOCMRPC;
883                     reason = "AFS Service start failed";
884                     break;
885                 }
886             }
887
888             /* If the retry interval has expired and we still aren't
889              * logged in, then just give up if we are not in interactive
890              * mode or the failSilently flag is set, otherwise let the
891              * user know we failed and give them a chance to try again. */
892             if (retryInterval <= 0) {
893                 reason = "AFS not running";
894                 if (!interactive || opt.failSilently)
895                     break;
896                 flag = MessageBox(hwndOwner,
897                                    "AFS is still starting.  Retry?",
898                                    "AFS Logon",
899                                    MB_ICONQUESTION | MB_RETRYCANCEL);
900                 if (flag == IDCANCEL)
901                     break;
902
903                 /* Wait just a little while and try again */
904                 retryInterval = opt.retryInterval;
905             }
906
907           sleeping:
908             Sleep(sleepInterval * 1000);
909             retryInterval -= sleepInterval;
910         }
911     }
912     DebugEvent("while loop exited");
913     /* remove any kerberos 5 tickets currently held by the SYSTEM account
914      * for this user 
915      */
916     if ( KFW_is_available() ) {
917         sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
918         KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
919
920         KFW_AFS_destroy_tickets_for_principal(uname);
921     }
922
923     if (code) {
924         char msg[128];
925         HANDLE h;
926         char *ptbuf[1];
927
928         StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
929
930         if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
931             MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
932
933         h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
934         ptbuf[0] = msg;
935         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
936                      1, 0, ptbuf, NULL);
937         DeregisterEventSource(h);
938             
939         code = MapAuthError(code);
940         SetLastError(code);
941
942         if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
943         {
944             if (*lpLogonScript)
945                 LocalFree(*lpLogonScript);
946             *lpLogonScript = NULL;
947             if (!afsWillAutoStart)      // its not running, so if not autostart or integrated logon then just skip
948                 code = 0;
949         }
950     }
951
952     if (opt.theseCells) free(opt.theseCells);
953     if (opt.smbName) free(opt.smbName);
954
955     DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
956     return code;
957 }       
958
959 DWORD APIENTRY NPPasswordChangeNotify(
960         LPCWSTR lpAuthentInfoType,
961         LPVOID lpAuthentInfo,
962         LPCWSTR lpPreviousAuthentInfoType,
963         LPVOID lpPreviousAuthentInfo,
964         LPWSTR lpStationName,
965         LPVOID StationHandle,
966         DWORD dwChangeInfo)
967 {
968     /* Make sure the AFS Libraries are initialized */
969     AfsLogonInit();
970
971     DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
972     return 0;
973 }
974
975 #include <userenv.h>
976 #include <Winwlx.h>
977 #include <afs/vice.h>
978 #include <afs/fs_utils.h>
979
980 BOOL IsPathInAfs(const CHAR *strPath)
981 {
982     char space[2048];
983     struct ViceIoctl blob;
984     int code;
985
986     blob.in_size = 0;
987     blob.out_size = 2048;
988     blob.out = space;
989
990     code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
991     if (code)
992         return FALSE;
993     return TRUE;
994 }
995
996 #ifdef COMMENT
997 typedef struct _WLX_NOTIFICATION_INFO {  
998     ULONG Size;  
999     ULONG Flags;  
1000     PWSTR UserName;  
1001     PWSTR Domain;  
1002     PWSTR WindowStation;  
1003     HANDLE hToken;  
1004     HDESK hDesktop;  
1005     PFNMSGECALLBACK pStatusCallback;
1006 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
1007 #endif
1008
1009 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
1010 {
1011     DWORD LSPtype, LSPsize;
1012     HKEY NPKey;
1013
1014     /* Make sure the AFS Libraries are initialized */
1015     AfsLogonInit();
1016
1017     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1018                         0, KEY_QUERY_VALUE, &NPKey);
1019     LSPsize=sizeof(TraceOption);
1020     RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
1021                      &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
1022
1023     RegCloseKey (NPKey);
1024     DebugEvent0("AFS_Startup_Event");
1025 }
1026
1027 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
1028 {
1029     DWORD code;
1030     TCHAR profileDir[1024] = TEXT("");
1031     DWORD  len = 1024;
1032     PTOKEN_USER  tokenUser = NULL;
1033     DWORD  retLen;
1034     DWORD LSPtype, LSPsize;
1035     HKEY NPKey;
1036     DWORD LogoffPreserveTokens = 0;
1037     LogonOptions_t opt;
1038
1039     /* Make sure the AFS Libraries are initialized */
1040     AfsLogonInit();
1041
1042     DebugEvent0("AFS_Logoff_Event - Start");
1043
1044     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1045                          0, KEY_QUERY_VALUE, &NPKey);
1046     LSPsize=sizeof(LogoffPreserveTokens);
1047     RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
1048                      &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
1049     RegCloseKey (NPKey);
1050
1051     ZeroMemory(&opt, sizeof(opt));
1052
1053     if (pInfo->UserName && pInfo->Domain) {
1054         char username[MAX_USERNAME_LENGTH] = "";
1055         char domain[MAX_DOMAIN_LENGTH] = "";
1056         size_t szlen = 0;
1057
1058         StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1059         WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1060                             username, sizeof(username), NULL, NULL);
1061
1062         StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1063         WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1064                             domain, sizeof(domain), NULL, NULL);
1065
1066         GetDomainLogonOptions(NULL, username, domain, &opt);
1067     }
1068
1069     if (!LogoffPreserveTokens &&
1070         ISLOGONINTEGRATED(opt.LogonOption) &&
1071         ISREMOTE(opt.flags)) {
1072
1073         if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1074         {
1075             if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1076                 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1077
1078                 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1079                 {
1080                     DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1081                 }
1082             }
1083         }
1084
1085         /* We can't use pInfo->Domain for the domain since in the cross realm case 
1086          * this is source domain and not the destination domain.
1087          */
1088         if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1089             WCHAR Domain[64]=L"";
1090             GetLocalShortDomain(Domain, sizeof(Domain));
1091             if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1092                 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1093                     GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1094             }
1095         }
1096
1097         if (strlen(profileDir)) {
1098             DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1099             if (!IsPathInAfs(profileDir)) {
1100                 if (code = ktc_ForgetAllTokens())
1101                     DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1102                 else
1103                     DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1104             } else {
1105                 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1106             }
1107         } else {
1108             DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1109         }
1110
1111         if ( tokenUser )
1112             LocalFree(tokenUser);
1113     }
1114
1115     DebugEvent0("AFS_Logoff_Event - End");
1116 }   
1117
1118 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1119 {
1120     TCHAR profileDir[1024] = TEXT("");
1121     DWORD  len = 1024;
1122     PTOKEN_USER  tokenUser = NULL;
1123     DWORD  retLen;
1124     WCHAR szUserW[128] = L"";
1125     char  szUserA[128] = "";
1126     char  szClient[MAX_PATH];
1127     char szPath[MAX_PATH] = "";
1128     NETRESOURCE nr;
1129     DWORD res;
1130     DWORD dwSize;
1131     LogonOptions_t opt;
1132
1133     /* Make sure the AFS Libraries are initialized */
1134     AfsLogonInit();
1135
1136     DebugEvent0("AFS_Logon_Event - Start");
1137
1138     DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1139
1140     ZeroMemory(&opt, sizeof(opt));
1141
1142     if (pInfo->UserName && pInfo->Domain) {
1143         char username[MAX_USERNAME_LENGTH] = "";
1144         char domain[MAX_DOMAIN_LENGTH] = "";
1145         size_t szlen = 0;
1146
1147         StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1148         WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1149                             username, sizeof(username), NULL, NULL);
1150         
1151         StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1152         WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1153                             domain, sizeof(domain), NULL, NULL);
1154
1155         GetDomainLogonOptions(NULL, username, domain, &opt);
1156     }
1157
1158     if (!ISLOGONINTEGRATED(opt.LogonOption) || !ISREMOTE(opt.flags)) {
1159         DebugEvent("AFS_Logon_Event - Logon is not integrated or not remote");
1160         goto done_logon_event;
1161     }
1162
1163     if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1164     {
1165         if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1166             tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1167
1168             if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1169             {
1170                 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1171             }
1172         }
1173     }
1174
1175     /* We can't use pInfo->Domain for the domain since in the cross realm case 
1176      * this is source domain and not the destination domain.
1177      */
1178     if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1179         WCHAR Domain[64]=L"";
1180         GetLocalShortDomain(Domain, sizeof(Domain));
1181         if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1182             if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1183                 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1184         }
1185     }
1186     
1187     if (strlen(profileDir)) {
1188         DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1189     } else {
1190         DebugEvent0("AFS_Logon_Event - Unable to load profile");
1191     }
1192
1193     dwSize = sizeof(szUserA);
1194     if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1195         StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1196         WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1197     }
1198
1199     if (szUserA[0])
1200     {
1201         lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1202         StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1203
1204         DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1205
1206         memset (&nr, 0x00, sizeof(NETRESOURCE));
1207         nr.dwType=RESOURCETYPE_DISK;
1208         nr.lpLocalName=0;
1209         nr.lpRemoteName=szPath;
1210         res = WNetAddConnection2(&nr,NULL,szUserA,0);
1211         if (res)
1212             DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1213                         szPath, szUserA,res);
1214         else
1215             DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1216     } else 
1217         DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1218
1219     if ( tokenUser )
1220         LocalFree(tokenUser);
1221
1222  done_logon_event:
1223     DebugEvent0("AFS_Logon_Event - End");
1224 }
1225
1226 static BOOL
1227 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1228 {
1229     NTSTATUS Status = 0;
1230     TOKEN_STATISTICS Stats;
1231     DWORD   ReqLen;
1232     BOOL    Success;
1233
1234     if (!ppSessionData)
1235         return FALSE;
1236     *ppSessionData = NULL;
1237
1238     Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1239     if ( !Success )
1240         return FALSE;
1241
1242     Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1243     if ( FAILED(Status) || !ppSessionData )
1244         return FALSE;
1245
1246     return TRUE;
1247 }
1248
1249 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1250 {
1251     WCHAR szUserW[128] = L"";
1252     char  szUserA[128] = "";
1253     char szPath[MAX_PATH] = "";
1254     char szLogonId[128] = "";
1255     DWORD count;
1256     char filename[256];
1257     char commandline[512];
1258     STARTUPINFO startupinfo;
1259     PROCESS_INFORMATION procinfo;
1260
1261     LUID LogonId = {0, 0};
1262     PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1263
1264     HKEY hKey1 = NULL, hKey2 = NULL;
1265
1266     /* Make sure the KFW Libraries are initialized */
1267     AfsLogonInit();
1268
1269     DebugEvent0("KFW_Logon_Event - Start");
1270
1271     GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1272
1273     if ( pLogonSessionData ) {
1274         LogonId = pLogonSessionData->LogonId;
1275         DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1276
1277         sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1278         LsaFreeReturnBuffer( pLogonSessionData );
1279     } else {
1280         DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1281         return;
1282     }
1283
1284     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1285     if ( count > sizeof(filename) || count == 0 ) {
1286         GetWindowsDirectory(filename, sizeof(filename));
1287     }
1288
1289     if ( strlen(filename) + strlen(szLogonId) + 2 <= sizeof(filename) ) {
1290         strcat(filename, "\\");
1291         strcat(filename, szLogonId);    
1292
1293         sprintf(commandline, "afscpcc.exe \"%s\"", filename);
1294
1295         GetStartupInfo(&startupinfo);
1296         if (CreateProcessAsUser( pInfo->hToken,
1297                              "afscpcc.exe",
1298                              commandline,
1299                              NULL,
1300                              NULL,
1301                              FALSE,
1302                              CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1303                              NULL,
1304                              NULL,
1305                              &startupinfo,
1306                              &procinfo)) 
1307         {
1308             WaitForSingleObject(procinfo.hProcess, 30000);
1309
1310             CloseHandle(procinfo.hThread);
1311             CloseHandle(procinfo.hProcess);
1312         }
1313     }
1314
1315     DeleteFile(filename);
1316
1317     DebugEvent0("KFW_Logon_Event - End");
1318 }
1319