Windows: afslogon.dll vs windows 7
[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-DOMAINS sent from login that is sent to us is striped */
858     ctemp = strchr(uname, '@');
859     if (ctemp) {
860         *ctemp = 0;
861         ctemp++;
862         if ( logonDomain[0] == '\0' )
863             StringCchCopy(logonDomain, MAX_DOMAIN_LENGTH, ctemp);
864     }
865
866     /* is the name all lowercase? */
867     for ( ctemp = uname; *ctemp ; ctemp++) {
868         if ( !islower(*ctemp) ) {
869             lowercased_name = FALSE;
870             break;
871         }
872     }
873
874     /*
875      * Get Logon options
876      */
877
878     GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
879     retryInterval = opt.retryInterval;
880     sleepInterval = opt.sleepInterval;
881     *lpLogonScript = opt.logonScript;
882
883     if (retryInterval < sleepInterval)
884         sleepInterval = retryInterval;
885
886     DebugEvent("Got logon script: %S",opt.logonScript);
887
888     afsWillAutoStart = AFSWillAutoStart();
889
890     DebugEvent("LogonOption[%x], Service AutoStart[%d]",
891                 opt.LogonOption,afsWillAutoStart);
892     
893     /* Check for zero length password if integrated logon*/
894     if ( ISLOGONINTEGRATED(opt.LogonOption) )  {
895         if ( password[0] == 0 ) {
896             DebugEvent0("Password is the empty string");
897             code = GT_PW_NULL;
898             reason = "zero length password is illegal";
899             code=0;
900         }
901
902         /* Get cell name if doing integrated logon.  
903            We might overwrite this if we are logging into an AD realm and we find out that
904            the user's home dir is in some other cell. */
905         DebugEvent("About to call cm_GetRootCellName(%s)",cell);
906         code = cm_GetRootCellName(cell);
907         if (code < 0) { 
908             DebugEvent0("Unable to obtain Root Cell");
909             code = KTC_NOCELL;
910             reason = "unknown cell";
911             code=0;
912         } else {
913             DebugEvent("Cell is %s",cell);
914         }       
915
916         /* We get the user's home directory path, if applicable, though we can't lookup the
917            cell right away because the client service may not have started yet. This call
918            also sets the AD_REALM flag in opt.flags if applicable. */
919         if (ISREMOTE(opt.flags)) {
920             DebugEvent0("Is Remote");
921             GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
922         }
923     }
924
925     /* loop until AFS is started. */
926     if (afsWillAutoStart) {
927         while (IsServiceRunning() || IsServiceStartPending()) {
928             DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
929                         opt.LogonOption,afsWillAutoStart);
930
931             if (ISADREALM(opt.flags)) {
932                 code = GetFileCellName(homePath,cell,256);
933                 if (!code) {
934                     DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
935                 }
936                 /* Don't bail out if GetFileCellName failed.
937                  * The home dir may not be in AFS after all. 
938                  */
939             } else
940                 code=0;
941                 
942             /* if Integrated Logon  */
943             if (ISLOGONINTEGRATED(opt.LogonOption))
944             {                   
945                 if ( KFW_is_available() ) {
946                     SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
947                     if (opt.realm) {
948                         char * principal, *p;
949                         size_t len, tlen;
950
951                         StringCchLength(opt.realm, MAX_DOMAIN_LENGTH, &tlen);
952                         len = tlen;
953                         StringCchLength(uname, MAX_USERNAME_LENGTH, &tlen);
954                         len += tlen + 2;
955
956                         /* tlen is now the length of uname in characters */
957                         principal = (char *)malloc(len * sizeof(char));
958                         if ( principal ) {
959                             StringCchCopy(principal, len, uname);
960                             p = principal + tlen;
961                             *p++ = '@';
962                             StringCchCopy(p, len - tlen -1, opt.realm);
963                             code = KFW_AFS_get_cred(principal, cell, password, 0, opt.smbName, &reason);
964                             DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
965                                             principal,opt.smbName,cell,code);
966                             free(principal);
967                         }
968                     } else {
969                         code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
970                         DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
971                                     uname,opt.smbName,cell,code);
972                     }
973                     SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL);
974                     if (code == 0 && opt.theseCells) { 
975                         char * principal, *p;
976                         size_t len, tlen;
977
978                         StringCchLength(opt.realm ? opt.realm : cell, MAX_DOMAIN_LENGTH, &tlen);
979                         len = tlen;
980                         StringCchLength(uname, MAX_USERNAME_LENGTH, &tlen);
981                         len += tlen + 2;
982
983                         /* tlen is now the length of uname in characters */
984                         principal = (char *)malloc(len * sizeof(char));
985                         if ( principal ) {
986                             StringCchCopy(principal, len, uname);
987                             p = principal + tlen;
988                             *p++ = '@';
989                             if (opt.realm) {
990                                 StringCchCopy(p, len - tlen -1, opt.realm);
991                             } else {
992                                 StringCchCopy(p, len - tlen - 1, cell);
993                                 for ( ;*p; p++) {
994                                     *p = toupper(*p);
995                                 }
996                             }
997                             p = opt.theseCells;
998                             while ( *p ) {
999                                 if ( cm_stricmp_utf8(p, cell) ) {
1000                                     SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
1001                                     code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
1002                                     SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL);
1003                                     DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
1004                                                principal,opt.smbName,p,code2);
1005                                 }
1006                                 p += strlen(p) + 1;
1007                             }
1008                             free(principal);
1009                         }
1010                     }
1011                 } else {
1012                     code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
1013                                                         uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
1014                                                         &reason);
1015                     DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2 Code[%x] uname[%s] smbname=[%s] Cell[%s] PwExp=[%d] Reason=[%s]",
1016                                 code,uname,opt.smbName,cell,pw_exp,reason?reason:"");
1017                 }       
1018                 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
1019                     for ( ctemp = uname; *ctemp ; ctemp++) {
1020                         *ctemp = tolower(*ctemp);
1021                     }
1022                     lowercased_name = TRUE;
1023                     goto sleeping;
1024                 }
1025
1026                 /* is service started yet?*/
1027
1028                 /* If we've failed because the client isn't running yet and the
1029                  * client is set to autostart (and therefore it makes sense for
1030                  * us to wait for it to start) then sleep a while and try again. 
1031                  * If the error was something else, then give up. */
1032                 if (code != KTC_NOCM && code != KTC_NOCMRPC)
1033                     break;
1034             }
1035             else {  
1036                 /*JUST check to see if its running*/
1037                 if (IsServiceRunning())
1038                     break;
1039                 if (!IsServiceStartPending()) {
1040                     code = KTC_NOCMRPC;
1041                     reason = "AFS Service start failed";
1042                     break;
1043                 }
1044             }
1045
1046             /* If the retry interval has expired and we still aren't
1047              * logged in, then just give up if we are not in interactive
1048              * mode or the failSilently flag is set, otherwise let the
1049              * user know we failed and give them a chance to try again. */
1050             if (retryInterval <= 0) {
1051                 reason = "AFS not running";
1052                 if (!interactive || opt.failSilently)
1053                     break;
1054                 flag = MessageBox(hwndOwner,
1055                                    "AFS is still starting.  Retry?",
1056                                    "AFS Logon",
1057                                    MB_ICONQUESTION | MB_RETRYCANCEL);
1058                 if (flag == IDCANCEL)
1059                     break;
1060
1061                 /* Wait just a little while and try again */
1062                 retryInterval = opt.retryInterval;
1063             }
1064
1065           sleeping:
1066             Sleep(sleepInterval * 1000);
1067             retryInterval -= sleepInterval;
1068         }
1069     }
1070     DebugEvent0("while loop exited");
1071
1072     /* remove any kerberos 5 tickets currently held by the SYSTEM account
1073      * for this user 
1074      */
1075
1076     if (ISLOGONINTEGRATED(opt.LogonOption) && KFW_is_available()) {
1077 #ifdef KFW_LOGON
1078         sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
1079         KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
1080 #endif
1081         KFW_AFS_destroy_tickets_for_principal(uname);
1082     }
1083
1084     if (code) {
1085         char msg[128];
1086         HANDLE h;
1087         char *ptbuf[1];
1088
1089         StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
1090
1091         if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
1092             MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
1093
1094         h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
1095         ptbuf[0] = msg;
1096         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
1097                      1, 0, ptbuf, NULL);
1098         DeregisterEventSource(h);
1099             
1100         code = MapAuthError(code);
1101         SetLastError(code);
1102
1103         if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
1104         {
1105             if (*lpLogonScript)
1106                 LocalFree(*lpLogonScript);
1107             *lpLogonScript = NULL;
1108             if (!afsWillAutoStart)      // its not running, so if not autostart or integrated logon then just skip
1109                 code = 0;
1110         }
1111     }
1112
1113     if (opt.theseCells) free(opt.theseCells);
1114     if (opt.smbName) free(opt.smbName);
1115     if (opt.realm) free(opt.realm);
1116
1117     DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
1118     return code;
1119 }       
1120
1121 DWORD APIENTRY NPPasswordChangeNotify(
1122         LPCWSTR lpAuthentInfoType,
1123         LPVOID lpAuthentInfo,
1124         LPCWSTR lpPreviousAuthentInfoType,
1125         LPVOID lpPreviousAuthentInfo,
1126         LPWSTR lpStationName,
1127         LPVOID StationHandle,
1128         DWORD dwChangeInfo)
1129 {
1130     BOOLEAN interactive;
1131
1132     /* Are we interactive? */
1133     interactive = (wcsicmp(lpStationName, L"WinSta0") == 0);
1134
1135     /* Do not do anything if the logon session is not interactive. */
1136     if (!interactive)
1137         return 0;
1138
1139     /* Make sure the AFS Libraries are initialized */
1140     AfsLogonInit();
1141
1142     DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
1143     return 0;
1144 }
1145
1146 #include <userenv.h>
1147 #include <Winwlx.h>
1148 #include <afs/vice.h>
1149 #include <afs/fs_utils.h>
1150
1151 BOOL IsPathInAfs(const CHAR *strPath)
1152 {
1153     char space[2048];
1154     struct ViceIoctl blob;
1155     int code;
1156
1157     blob.in_size = 0;
1158     blob.out_size = 2048;
1159     blob.out = space;
1160
1161     code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
1162     if (code)
1163         return FALSE;
1164     return TRUE;
1165 }
1166
1167 #ifdef COMMENT
1168 typedef struct _WLX_NOTIFICATION_INFO {  
1169     ULONG Size;  
1170     ULONG Flags;  
1171     PWSTR UserName;  
1172     PWSTR Domain;  
1173     PWSTR WindowStation;  
1174     HANDLE hToken;  
1175     HDESK hDesktop;  
1176     PFNMSGECALLBACK pStatusCallback;
1177 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
1178 #endif
1179
1180 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
1181 {
1182     DWORD LSPtype, LSPsize;
1183     HKEY NPKey;
1184
1185     /* Make sure the AFS Libraries are initialized */
1186     AfsLogonInit();
1187
1188     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1189                         0, KEY_QUERY_VALUE, &NPKey);
1190     LSPsize=sizeof(TraceOption);
1191     RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
1192                      &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
1193
1194     RegCloseKey (NPKey);
1195     DebugEvent0("AFS_Startup_Event");
1196 }
1197
1198 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
1199 {
1200     DWORD code;
1201     TCHAR profileDir[1024] = TEXT("");
1202     DWORD  len = 1024;
1203     PTOKEN_USER  tokenUser = NULL;
1204     DWORD  retLen;
1205     DWORD LSPtype, LSPsize;
1206     HKEY NPKey;
1207     DWORD LogoffPreserveTokens = 0;
1208     LogonOptions_t opt;
1209
1210     /* Make sure the AFS Libraries are initialized */
1211     AfsLogonInit();
1212
1213     DebugEvent0("AFS_Logoff_Event - Start");
1214
1215     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1216                          0, KEY_QUERY_VALUE, &NPKey);
1217     LSPsize=sizeof(LogoffPreserveTokens);
1218     RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
1219                      &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
1220     RegCloseKey (NPKey);
1221
1222     if (!LogoffPreserveTokens) {
1223         memset(&opt, 0, sizeof(LogonOptions_t));
1224
1225         if (pInfo->UserName && pInfo->Domain) {
1226             char username[MAX_USERNAME_LENGTH] = "";
1227             char domain[MAX_DOMAIN_LENGTH] = "";
1228             size_t szlen = 0;
1229
1230             StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1231             WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1232                                  username, sizeof(username), NULL, NULL);
1233
1234             StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1235             WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1236                                  domain, sizeof(domain), NULL, NULL);
1237
1238             GetDomainLogonOptions(NULL, username, domain, &opt);
1239         }
1240
1241         if (ISREMOTE(opt.flags)) {
1242             if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1243             {
1244                 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1245                     tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1246
1247                     if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1248                     {
1249                         DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1250                     }
1251                 }
1252             }
1253
1254             /* We can't use pInfo->Domain for the domain since in the cross realm case 
1255              * this is source domain and not the destination domain.
1256              */
1257             if (tokenUser && QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1258                 WCHAR Domain[64]=L"";
1259                 GetLocalShortDomain(Domain, sizeof(Domain));
1260                 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1261                     if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1262                         GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1263                 }
1264             }
1265
1266             if (strlen(profileDir)) {
1267                 DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1268                 if (!IsPathInAfs(profileDir)) {
1269                     if (code = ktc_ForgetAllTokens())
1270                         DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1271                     else
1272                         DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1273                 } else {
1274                     DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1275                 }
1276             } else {
1277                 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1278             }
1279
1280             if ( tokenUser )
1281                 LocalFree(tokenUser);
1282         } else {
1283             DebugEvent0("AFS_Logoff_Event - Local Logon");
1284             if (code = ktc_ForgetAllTokens())
1285                 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1286             else
1287                 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1288         }
1289     } else {
1290         DebugEvent0("AFS_Logoff_Event - Preserving Tokens");
1291     }
1292
1293     DebugEvent0("AFS_Logoff_Event - End");
1294 }   
1295
1296 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1297 {
1298     TCHAR profileDir[1024] = TEXT("");
1299     DWORD  len = 1024;
1300     PTOKEN_USER  tokenUser = NULL;
1301     DWORD  retLen;
1302     WCHAR szUserW[128] = L"";
1303     char  szUserA[128] = "";
1304     char  szClient[MAX_PATH];
1305     char szPath[MAX_PATH] = "";
1306     NETRESOURCE nr;
1307     DWORD res;
1308     DWORD dwSize;
1309     LogonOptions_t opt;
1310
1311     /* Make sure the AFS Libraries are initialized */
1312     AfsLogonInit();
1313
1314     DebugEvent0("AFS_Logon_Event - Start");
1315
1316     DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1317
1318     memset(&opt, 0, sizeof(LogonOptions_t));
1319
1320     if (pInfo->UserName && pInfo->Domain) {
1321         char username[MAX_USERNAME_LENGTH] = "";
1322         char domain[MAX_DOMAIN_LENGTH] = "";
1323         size_t szlen = 0;
1324
1325         DebugEvent0("AFS_Logon_Event - pInfo UserName and Domain");
1326
1327         StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1328         WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1329                             username, sizeof(username), NULL, NULL);
1330         
1331         StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1332         WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1333                             domain, sizeof(domain), NULL, NULL);
1334
1335         DebugEvent0("AFS_Logon_Event - Calling GetDomainLogonOptions");
1336         GetDomainLogonOptions(NULL, username, domain, &opt);
1337     } else {
1338         if (!pInfo->UserName)
1339             DebugEvent0("AFS_Logon_Event - No pInfo->UserName");
1340         if (!pInfo->Domain)
1341             DebugEvent0("AFS_Logon_Event - No pInfo->Domain");
1342     }
1343
1344     DebugEvent("AFS_Logon_Event - opt.LogonOption = %lX opt.flags = %lX", 
1345                 opt.LogonOption, opt.flags);
1346
1347     if (!ISLOGONINTEGRATED(opt.LogonOption) || !ISREMOTE(opt.flags)) {
1348         DebugEvent0("AFS_Logon_Event - Logon is not integrated or not remote");
1349         goto done_logon_event;
1350     }
1351
1352     DebugEvent0("AFS_Logon_Event - Calling GetTokenInformation");
1353
1354     if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1355     {
1356         if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1357             tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1358
1359             if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1360             {
1361                 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1362             }
1363         }
1364     }
1365
1366     /* We can't use pInfo->Domain for the domain since in the cross realm case 
1367      * this is source domain and not the destination domain.
1368      */
1369     if (tokenUser && QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1370         WCHAR Domain[64]=L"";
1371         GetLocalShortDomain(Domain, sizeof(Domain));
1372         if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1373             if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1374                 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1375         }
1376     }
1377     
1378     if (strlen(profileDir)) {
1379         DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1380     } else {
1381         DebugEvent0("AFS_Logon_Event - Unable to load profile");
1382     }
1383
1384   done_logon_event:
1385     dwSize = sizeof(szUserA);
1386     if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1387         StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1388         WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1389     }
1390
1391     if (szUserA[0])
1392     {
1393         lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1394         StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1395
1396         DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1397
1398         memset (&nr, 0x00, sizeof(NETRESOURCE));
1399         nr.dwType=RESOURCETYPE_DISK;
1400         nr.lpLocalName=0;
1401         nr.lpRemoteName=szPath;
1402         res = WNetAddConnection2(&nr,NULL,szUserA,0);
1403         if (res)
1404             DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1405                         szPath, szUserA,res);
1406         else
1407             DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1408     } else 
1409         DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1410
1411     if ( tokenUser )
1412         LocalFree(tokenUser);
1413
1414     DebugEvent0("AFS_Logon_Event - End");
1415 }
1416
1417 static BOOL
1418 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1419 {
1420     NTSTATUS Status = 0;
1421     TOKEN_STATISTICS Stats;
1422     DWORD   ReqLen;
1423     BOOL    Success;
1424
1425     if (!ppSessionData)
1426         return FALSE;
1427     *ppSessionData = NULL;
1428
1429     Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1430     if ( !Success )
1431         return FALSE;
1432
1433     Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1434     if ( FAILED(Status) || !ppSessionData )
1435         return FALSE;
1436
1437     return TRUE;
1438 }
1439
1440 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1441 {
1442 #ifdef KFW_LOGON
1443     WCHAR szUserW[128] = L"";
1444     char  szUserA[128] = "";
1445     char szPath[MAX_PATH] = "";
1446     char szLogonId[128] = "";
1447     DWORD count;
1448     char filename[MAX_PATH] = "";
1449     char newfilename[MAX_PATH] = "";
1450     char commandline[MAX_PATH+256] = "";
1451     STARTUPINFO startupinfo;
1452     PROCESS_INFORMATION procinfo;
1453     HANDLE hf = INVALID_HANDLE_VALUE;
1454
1455     LUID LogonId = {0, 0};
1456     PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1457
1458     HKEY hKey1 = NULL, hKey2 = NULL;
1459
1460     /* Make sure the KFW Libraries are initialized */
1461     AfsLogonInit();
1462
1463     DebugEvent0("KFW_Logon_Event - Start");
1464
1465     GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1466
1467     if ( pLogonSessionData ) {
1468         LogonId = pLogonSessionData->LogonId;
1469         DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1470
1471         sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1472         LsaFreeReturnBuffer( pLogonSessionData );
1473     } else {
1474         DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1475         return;
1476     }
1477
1478     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1479     if ( count > sizeof(filename) || count == 0 ) {
1480         GetWindowsDirectory(filename, sizeof(filename));
1481     }
1482
1483     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1484     if ( count > sizeof(filename) || count == 0 ) {
1485         GetWindowsDirectory(filename, sizeof(filename));
1486     }
1487
1488     if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) {
1489         DebugEvent0("KFW_Logon_Event - filename too long");
1490         return;
1491     }
1492
1493     strcat(filename, "\\");
1494     strcat(filename, szLogonId);    
1495
1496     hf = CreateFile(filename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING, 
1497                      FILE_ATTRIBUTE_NORMAL, NULL);
1498     if (hf == INVALID_HANDLE_VALUE) {
1499         DebugEvent0("KFW_Logon_Event - file cannot be opened");
1500         return;
1501     }
1502     CloseHandle(hf);
1503  
1504     if (KFW_AFS_set_file_cache_dacl(filename, pInfo->hToken)) {
1505         DebugEvent0("KFW_Logon_Event - unable to set dacl");
1506         DeleteFile(filename);
1507         return;
1508     }
1509  
1510     if (KFW_AFS_obtain_user_temp_directory(pInfo->hToken, newfilename, sizeof(newfilename))) {
1511         DebugEvent0("KFW_Logon_Event - unable to obtain temp directory");
1512         return;
1513     }
1514
1515     if ( strlen(newfilename) + strlen(szLogonId) + 2 > sizeof(newfilename) ) {
1516         DebugEvent0("KFW_Logon_Event - new filename too long");
1517         return;
1518     }
1519
1520     strcat(newfilename, "\\");
1521     strcat(newfilename, szLogonId);    
1522
1523     if (!MoveFileEx(filename, newfilename, 
1524                      MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
1525         DebugEvent("KFW_Logon_Event - MoveFileEx failed GLE = 0x%x", GetLastError());
1526         return;
1527     }
1528
1529     sprintf(commandline, "afscpcc.exe \"%s\"", newfilename);
1530
1531     GetStartupInfo(&startupinfo);
1532     if (CreateProcessAsUser( pInfo->hToken,
1533                              "afscpcc.exe",
1534                              commandline,
1535                              NULL,
1536                              NULL,
1537                              FALSE,
1538                              CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1539                              NULL,
1540                              NULL,
1541                              &startupinfo,
1542                              &procinfo)) 
1543     {
1544         DebugEvent("KFW_Logon_Event - CommandLine %s", commandline);
1545
1546         WaitForSingleObject(procinfo.hProcess, 30000);
1547
1548         CloseHandle(procinfo.hThread);
1549         CloseHandle(procinfo.hProcess);
1550     } else {
1551         DebugEvent0("KFW_Logon_Event - CreateProcessFailed");
1552     }
1553
1554     DeleteFile(filename);
1555
1556     DebugEvent0("KFW_Logon_Event - End");
1557 #endif
1558 }
1559