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