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