windows-network-type-allocation-20080128
[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;
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;
372         if(GetComputerName(computerName, &dwSize)) {
373             if(!stricmp(computerName, domain)) {
374                 effDomain = "LOCALHOST";
375                 opt->flags = LOGON_FLAG_LOCAL;
376             }
377             else
378                 effDomain = domain;
379         }
380     } else
381         effDomain = NULL;
382
383     rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, KEY_READ, &hkParm );
384     if(rv != ERROR_SUCCESS) {
385         hkParm = NULL;
386         DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
387     }
388
389     rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PROVIDER_SUBKEY, 0, KEY_READ, &hkNp );
390     if(rv != ERROR_SUCCESS) {
391         hkNp = NULL;
392         DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
393     }
394
395     if(hkNp) {
396         rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
397         if( rv != ERROR_SUCCESS ) {
398             hkDoms = NULL;
399             DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
400         }
401     }
402
403     if(hkDoms && effDomain) {
404         rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
405         if( rv != ERROR_SUCCESS ) {
406             hkDom = NULL;
407             DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
408             /* If none of the domains match, we shouldn't use the domain key either */
409             RegCloseKey(hkDoms);
410             hkDoms = NULL;
411         }
412     } else
413         DebugEvent0("Not opening domain key");
414
415     /* Each individual can either be specified on the domain key, the domains key or in the
416        net provider key.  They fail over in that order.  If none is found, we just use the 
417        defaults. */
418
419     /* LogonOption */
420     LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
421
422     /* FailLoginsSilently */
423     dwSize = sizeof(dwDummy);
424     rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
425     if (rv != ERROR_SUCCESS)
426         LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
427     opt->failSilently = !!dwDummy;
428
429     /* Retry interval */
430     LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
431
432     /* Sleep interval */
433     LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
434
435     opt->logonScript = NULL;
436     opt->smbName = NULL;
437
438     if(!ISLOGONINTEGRATED(opt->LogonOption)) {
439         goto cleanup; /* no need to lookup the logon script */
440     }
441
442     /* come up with SMB username */
443     if(ISHIGHSECURITY(opt->LogonOption)) {
444         opt->smbName = malloc( MAXRANDOMNAMELEN );
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;
450         char lsaUsername[MAX_USERNAME_LENGTH];
451         char lsaDomain[MAX_DOMAIN_LENGTH];
452         size_t len, tlen;
453
454         LsaGetLogonSessionData(lpLogonId, &plsd);
455         
456         UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
457         UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
458
459         DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
460
461         if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
462             len = tlen;
463         else
464             goto bad_strings;
465
466         if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
467             len += tlen;
468         else
469             goto bad_strings;
470
471         len += 2;
472
473         opt->smbName = malloc(len);
474
475         StringCbCopy(opt->smbName, len, lsaDomain);
476         StringCbCat(opt->smbName, len, "\\");
477         StringCbCat(opt->smbName, len, lsaUsername);
478
479         strlwr(opt->smbName);
480
481       bad_strings:
482         LsaFreeReturnBuffer(plsd);
483     } else {
484         size_t len;
485
486         DebugEvent("No LUID given. Constructing username using [%s] and [%s]",
487                    username, domain);
488  
489         len = strlen(username) + strlen(domain) + 2;
490
491         opt->smbName = malloc(len);
492
493         StringCbCopy(opt->smbName, len, username);
494         StringCbCat(opt->smbName, len, "\\");
495         StringCbCat(opt->smbName, len, domain);
496
497         strlwr(opt->smbName);
498     }
499
500     DebugEvent0("Looking up logon script");
501     /* Logon script */
502     /* First find out where the key is */
503     hkTemp = NULL;
504     rv = ~ERROR_SUCCESS;
505     dwType = 0;
506     if(hkDom)
507         rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
508     if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
509         hkTemp = hkDom;
510         DebugEvent0("Located logon script in hkDom");
511     }
512     else if(hkDoms) {
513         rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
514         if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
515             hkTemp = hkDoms;
516             DebugEvent0("Located logon script in hkDoms");
517         }
518         /* Note that the LogonScript in the NP key is only used if we are doing high security. */
519         else if(hkNp && ISHIGHSECURITY(opt->LogonOption)) {
520             rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
521             if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
522                 hkTemp = hkNp;
523                 DebugEvent0("Located logon script in hkNp");
524             }
525         }
526     }
527
528     if(hkTemp) {
529         WCHAR *regscript        = NULL;
530         WCHAR *regexscript      = NULL;
531         WCHAR *regexuscript     = NULL;
532         WCHAR *wuname           = NULL;
533         HRESULT hr;
534
535         size_t len;
536
537         StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
538         len ++;
539
540         wuname = malloc(len * sizeof(WCHAR));
541         if (!wuname)
542             goto doneLogonScript;
543         MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,(int)(len*sizeof(WCHAR)));
544
545         DebugEvent("Username is set for [%S]", wuname);
546
547         /* dwSize still has the size of the required buffer in bytes. */
548         regscript = malloc(dwSize);
549         if (!regscript)
550             goto doneLogonScript;
551         rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
552         if(rv != ERROR_SUCCESS) {/* what the ..? */
553             DebugEvent("Can't look up logon script rv [%d] size [%d] gle %d",rv, dwSize, GetLastError());
554             goto doneLogonScript;
555         }
556
557         DebugEvent("Found logon script [%S]", regscript);
558
559         if(dwType == REG_EXPAND_SZ) {
560             DWORD dwReq;
561
562             dwSize += MAX_PATH * sizeof(WCHAR);  /* make room for environment expansion. */
563             regexscript = malloc(dwSize);
564             if (!regexscript)
565                 goto doneLogonScript;
566             dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
567             free(regscript);
568             regscript = regexscript;
569             regexscript = NULL;
570             if(dwReq > (dwSize / sizeof(WCHAR))) {
571                 DebugEvent0("Overflow while expanding environment strings.");
572                 goto doneLogonScript;
573             }
574         }
575
576         DebugEvent("After expanding env strings [%S]", regscript);
577
578         if(wcsstr(regscript, L"%s")) {
579             dwSize += (DWORD)(len * sizeof(WCHAR)); /* make room for username expansion */
580             regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
581             if (!regexuscript)
582                 goto doneLogonScript;
583             hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
584         } else {
585             regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
586             if (!regexuscript)
587                 goto doneLogonScript;
588             hr = StringCbCopyW(regexuscript, dwSize, regscript);
589         }
590
591         DebugEvent("After expanding username [%S]", regexuscript);
592
593         if(hr == S_OK)
594             opt->logonScript = regexuscript;
595         else
596             LocalFree(regexuscript);
597
598       doneLogonScript:
599         if(wuname) free(wuname);
600         if(regscript) free(regscript);
601         if(regexscript) free(regexscript);
602     }
603
604     DebugEvent0("Looking up TheseCells");
605     /* TheseCells */
606     /* First find out where the key is */
607     hkTemp = NULL;
608     rv = ~ERROR_SUCCESS;
609     dwSize = 0;
610     if (hkDom)
611         rv = RegQueryValueEx(hkDom, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
612     if (rv == ERROR_SUCCESS && dwType == REG_MULTI_SZ) {
613         hkTemp = hkDom;
614         DebugEvent("Located TheseCells in hkDom size %d", dwSize);
615     } else if (hkDoms) {
616         rv = RegQueryValueEx(hkDoms, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
617         if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
618             hkTemp = hkDoms;
619             DebugEvent("Located TheseCells in hkDoms size %d", dwSize);
620         } else if (hkNp) {
621             rv = RegQueryValueEx(hkNp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
622             if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
623                 hkTemp = hkNp;
624                 DebugEvent("Located TheseCells in hkNp size %d", dwSize);
625             }
626         }
627     }
628
629     if (hkTemp) {
630         CHAR * thesecells = NULL;
631
632         /* dwSize still has the size of the required buffer in bytes. */
633         thesecells = malloc(dwSize*2);
634         if (!thesecells)
635             goto doneTheseCells;
636         dwSize *= 2;
637         SetLastError(0);
638         rv = RegQueryValueEx(hkTemp, REG_CLIENT_THESE_CELLS_PARM, 0, NULL, (LPBYTE) thesecells, &dwSize);
639         if(rv != ERROR_SUCCESS) {/* what the ..? */
640             DebugEvent("Can't look up TheseCells rv [%d] size [%d] gle [%d]",rv, dwSize, GetLastError());
641             goto doneTheseCells;
642         }
643
644         DebugEvent("Found TheseCells [%s]", thesecells);
645         opt->theseCells = thesecells;
646         thesecells = NULL;
647
648       doneTheseCells:
649         if (thesecells) free(thesecells);
650     }
651
652     DebugEvent0("Looking up Realm");
653     /* Realm */
654     /* First find out where the key is */
655     hkTemp = NULL;
656     rv = ~ERROR_SUCCESS;
657     dwSize = 0;
658     if (hkDom)
659         rv = RegQueryValueEx(hkDom, REG_CLIENT_REALM_PARM, 0, &dwType, NULL, &dwSize);
660     if (rv == ERROR_SUCCESS && dwType == REG_SZ) {
661         hkTemp = hkDom;
662         DebugEvent("Located Realm in hkDom size %d", dwSize);
663     } else if (hkDoms) {
664         rv = RegQueryValueEx(hkDoms, REG_CLIENT_REALM_PARM, 0, &dwType, NULL, &dwSize);
665         if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_SZ) {
666             hkTemp = hkDoms;
667             DebugEvent("Located Realm in hkDoms size %d", dwSize);
668         } else if (hkNp) {
669             rv = RegQueryValueEx(hkNp, REG_CLIENT_REALM_PARM, 0, &dwType, NULL, &dwSize);
670             if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_SZ) {
671                 hkTemp = hkNp;
672                 DebugEvent("Located Realm in hkNp size %d", dwSize);
673             }
674         }
675     }
676
677     if (hkTemp) {
678         CHAR * realm = NULL;
679
680         /* dwSize still has the size of the required buffer in bytes. */
681         realm = malloc(dwSize*2);
682         if (!realm)
683             goto doneRealm;
684         dwSize *=2;
685         SetLastError(0);
686         rv = RegQueryValueEx(hkTemp, REG_CLIENT_REALM_PARM, 0, NULL, (LPBYTE) realm, &dwSize);
687         if(rv != ERROR_SUCCESS) {/* what the ..? */
688             DebugEvent("Can't look up Realm rv [%d] size [%d] gle [%d]",rv, dwSize, GetLastError());
689             goto doneRealm;
690         }
691
692         DebugEvent("Found Realm [%s]", realm);
693         opt->realm = realm;
694         realm = NULL;
695
696       doneRealm:
697         if (realm) free(realm);
698     }
699
700   cleanup:
701     if(hkNp) RegCloseKey(hkNp);
702     if(hkDom) RegCloseKey(hkDom);
703     if(hkDoms) RegCloseKey(hkDoms);
704     if(hkParm) RegCloseKey(hkParm);
705 }       
706
707 #undef LOOKUPKEYCHAIN
708
709 /* Try to find out which cell the given path is in.  We must retain
710    the contents of *cell in case of failure. *cell is assumed to be
711    at least cellLen chars */
712 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
713     struct ViceIoctl blob;
714     char tcell[MAX_PATH];
715     DWORD code;
716
717     blob.in_size = 0;
718     blob.out_size = MAX_PATH;
719     blob.out = tcell;
720
721     code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
722
723     if(!code) {
724         strncpy(cell, tcell, cellLen);
725         cell[cellLen - 1] = '\0';
726     }
727     return code;
728 }       
729
730
731 static BOOL
732 WINAPI
733 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
734 {
735     CPINFO CodePageInfo;
736
737     GetCPInfo(CP_ACP, &CodePageInfo);
738
739     if (CodePageInfo.MaxCharSize > 1)
740         // Only supporting non-Unicode strings
741         return FALSE;
742     
743     if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
744     {
745         // Looks like unicode, better translate it
746         // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
747         WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
748                             lpszOutputString, nOutStringLen-1, NULL, NULL);
749         lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
750         return TRUE;
751     }
752       
753     lpszOutputString[0] = '\0';
754     return FALSE;
755 }  // UnicodeStringToANSI
756
757 DWORD APIENTRY NPLogonNotify(
758         PLUID lpLogonId,
759         LPCWSTR lpAuthentInfoType,
760         LPVOID lpAuthentInfo,
761         LPCWSTR lpPreviousAuthentInfoType,
762         LPVOID lpPreviousAuthentInfo,
763         LPWSTR lpStationName,
764         LPVOID StationHandle,
765         LPWSTR *lpLogonScript)
766 {
767     char uname[MAX_USERNAME_LENGTH]="";
768     char password[MAX_PASSWORD_LENGTH]="";
769     char logonDomain[MAX_DOMAIN_LENGTH]="";
770     char cell[256]="<non-integrated logon>";
771     char homePath[MAX_PATH]="";
772     char szLogonId[128] = "";
773
774     MSV1_0_INTERACTIVE_LOGON *IL;
775
776     DWORD code = 0, code2;
777
778     int pw_exp;
779     char *reason;
780     char *ctemp;
781
782     BOOLEAN interactive;
783     BOOLEAN flag;
784     DWORD LSPtype, LSPsize;
785     HKEY NPKey;
786
787     HWND hwndOwner = (HWND)StationHandle;
788
789     BOOLEAN afsWillAutoStart;
790
791     BOOLEAN lowercased_name = TRUE;
792
793     LogonOptions_t opt; /* domain specific logon options */
794     int retryInterval;
795     int sleepInterval;
796
797     /* Are we interactive? */
798     interactive = (wcsicmp(lpStationName, L"WinSta0") == 0);
799
800 #ifdef DISABLE_NON_INTERACTIVE
801     /* Do not do anything if the logon session is not interactive. */
802     if (!interactive)
803         return 0;
804 #endif
805
806     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
807                          0, KEY_QUERY_VALUE, &NPKey);
808     LSPsize=sizeof(TraceOption);
809     RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
810                      &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
811
812     RegCloseKey (NPKey);
813
814     DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart);
815
816     /* Make sure the AFS Libraries are initialized */
817     AfsLogonInit();
818
819     /* Initialize Logon Script to none */
820     *lpLogonScript=NULL;
821     
822     /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for
823      * our purposes */
824
825     if ( wcsicmp(lpAuthentInfoType,L"MSV1_0:Interactive") && 
826          wcsicmp(lpAuthentInfoType,L"Kerberos:Interactive") )
827     {
828         DebugEvent("Unsupported Authentication Info Type: %S",
829                    lpAuthentInfoType);
830         return 0;
831     }
832
833     IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
834
835     /* Convert from Unicode to ANSI */
836
837     /*TODO: Use SecureZeroMemory to erase passwords */
838     if (!UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH) ||
839          !UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH) ||
840          !UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH))
841         return 0;
842
843     /* Make sure AD-DOMANS sent from login that is sent to us is striped */
844     ctemp = strchr(uname, '@');
845     if (ctemp) *ctemp = 0;
846
847     /* is the name all lowercase? */
848     for ( ctemp = uname; *ctemp ; ctemp++) {
849         if ( !islower(*ctemp) ) {
850             lowercased_name = FALSE;
851             break;
852         }
853     }
854
855     /*
856      * Get Logon options
857      */
858
859     GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
860     retryInterval = opt.retryInterval;
861     sleepInterval = opt.sleepInterval;
862     *lpLogonScript = opt.logonScript;
863
864     if (retryInterval < sleepInterval)
865         sleepInterval = retryInterval;
866
867     DebugEvent("Got logon script: %S",opt.logonScript);
868
869     afsWillAutoStart = AFSWillAutoStart();
870
871     DebugEvent("LogonOption[%x], Service AutoStart[%d]",
872                 opt.LogonOption,afsWillAutoStart);
873     
874     /* Check for zero length password if integrated logon*/
875     if ( ISLOGONINTEGRATED(opt.LogonOption) )  {
876         if ( password[0] == 0 ) {
877             DebugEvent0("Password is the empty string");
878             code = GT_PW_NULL;
879             reason = "zero length password is illegal";
880             code=0;
881         }
882
883         /* Get cell name if doing integrated logon.  
884            We might overwrite this if we are logging into an AD realm and we find out that
885            the user's home dir is in some other cell. */
886         DebugEvent("About to call cm_GetRootCellName(%s)",cell);
887         code = cm_GetRootCellName(cell);
888         if (code < 0) { 
889             DebugEvent0("Unable to obtain Root Cell");
890             code = KTC_NOCELL;
891             reason = "unknown cell";
892             code=0;
893         } else {
894             DebugEvent("Cell is %s",cell);
895         }       
896
897         /* We get the user's home directory path, if applicable, though we can't lookup the
898            cell right away because the client service may not have started yet. This call
899            also sets the AD_REALM flag in opt.flags if applicable. */
900         if (ISREMOTE(opt.flags)) {
901             DebugEvent0("Is Remote");
902             GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
903         }
904     }
905
906     /* loop until AFS is started. */
907     if (afsWillAutoStart) {
908         while (IsServiceRunning() || IsServiceStartPending()) {
909             DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
910                         opt.LogonOption,afsWillAutoStart);
911
912             if (ISADREALM(opt.flags)) {
913                 code = GetFileCellName(homePath,cell,256);
914                 if (!code) {
915                     DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
916                 }
917                 /* Don't bail out if GetFileCellName failed.
918                  * The home dir may not be in AFS after all. 
919                  */
920             } else
921                 code=0;
922                 
923             /* if Integrated Logon  */
924             if (ISLOGONINTEGRATED(opt.LogonOption))
925             {                   
926                 if ( KFW_is_available() ) {
927                     SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
928                     if (opt.realm) {
929                         char * principal, *p;
930                         size_t len, tlen;
931
932                         StringCchLength(opt.realm, MAX_DOMAIN_LENGTH, &tlen);
933                         len = tlen;
934                         StringCchLength(uname, MAX_USERNAME_LENGTH, &tlen);
935                         len += tlen + 2;
936
937                         /* tlen is now the length of uname in characters */
938                         principal = (char *)malloc(len * sizeof(char));
939                         if ( principal ) {
940                             StringCchCopy(principal, len, uname);
941                             p = principal + tlen;
942                             *p++ = '@';
943                             StringCchCopy(p, len - tlen -1, opt.realm);
944                             code = KFW_AFS_get_cred(principal, cell, password, 0, opt.smbName, &reason);
945                             DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
946                                             principal,opt.smbName,cell,code);
947                             free(principal);
948                         }
949                     } else {
950                         code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
951                         DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
952                                     uname,opt.smbName,cell,code);
953                     }
954                     SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL);
955                     if (code == 0 && opt.theseCells) { 
956                         char * principal, *p;
957                         size_t len, tlen;
958
959                         StringCchLength(opt.realm ? opt.realm : cell, MAX_DOMAIN_LENGTH, &tlen);
960                         len = tlen;
961                         StringCchLength(uname, MAX_USERNAME_LENGTH, &tlen);
962                         len += tlen + 2;
963
964                         /* tlen is now the length of uname in characters */
965                         principal = (char *)malloc(len * sizeof(char));
966                         if ( principal ) {
967                             StringCchCopy(principal, len, uname);
968                             p = principal + tlen;
969                             *p++ = '@';
970                             if (opt.realm) {
971                                 StringCchCopy(p, len - tlen -1, opt.realm);
972                             } else {
973                                 StringCchCopy(p, len - tlen - 1, cell);
974                                 for ( ;*p; p++) {
975                                     *p = toupper(*p);
976                                 }
977                             }
978                             p = opt.theseCells;
979                             while ( *p ) {
980                                 if ( stricmp(p, cell) ) {
981                                     SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
982                                     code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
983                                     SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL);
984                                     DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
985                                                principal,opt.smbName,p,code2);
986                                 }
987                                 p += strlen(p) + 1;
988                             }
989                             free(principal);
990                         }
991                     }
992                 } else {
993                     code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
994                                                         uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
995                                                         &reason);
996                     DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2 Code[%x] uname[%s] smbname=[%s] Cell[%s] PwExp=[%d] Reason=[%s]",
997                                 code,uname,opt.smbName,cell,pw_exp,reason?reason:"");
998                 }       
999                 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
1000                     for ( ctemp = uname; *ctemp ; ctemp++) {
1001                         *ctemp = tolower(*ctemp);
1002                     }
1003                     lowercased_name = TRUE;
1004                     goto sleeping;
1005                 }
1006
1007                 /* is service started yet?*/
1008
1009                 /* If we've failed because the client isn't running yet and the
1010                  * client is set to autostart (and therefore it makes sense for
1011                  * us to wait for it to start) then sleep a while and try again. 
1012                  * If the error was something else, then give up. */
1013                 if (code != KTC_NOCM && code != KTC_NOCMRPC)
1014                     break;
1015             }
1016             else {  
1017                 /*JUST check to see if its running*/
1018                 if (IsServiceRunning())
1019                     break;
1020                 if (!IsServiceStartPending()) {
1021                     code = KTC_NOCMRPC;
1022                     reason = "AFS Service start failed";
1023                     break;
1024                 }
1025             }
1026
1027             /* If the retry interval has expired and we still aren't
1028              * logged in, then just give up if we are not in interactive
1029              * mode or the failSilently flag is set, otherwise let the
1030              * user know we failed and give them a chance to try again. */
1031             if (retryInterval <= 0) {
1032                 reason = "AFS not running";
1033                 if (!interactive || opt.failSilently)
1034                     break;
1035                 flag = MessageBox(hwndOwner,
1036                                    "AFS is still starting.  Retry?",
1037                                    "AFS Logon",
1038                                    MB_ICONQUESTION | MB_RETRYCANCEL);
1039                 if (flag == IDCANCEL)
1040                     break;
1041
1042                 /* Wait just a little while and try again */
1043                 retryInterval = opt.retryInterval;
1044             }
1045
1046           sleeping:
1047             Sleep(sleepInterval * 1000);
1048             retryInterval -= sleepInterval;
1049         }
1050     }
1051     DebugEvent0("while loop exited");
1052
1053     /* remove any kerberos 5 tickets currently held by the SYSTEM account
1054      * for this user 
1055      */
1056
1057     if (ISLOGONINTEGRATED(opt.LogonOption) && KFW_is_available()) {
1058 #ifdef KFW_LOGON
1059         sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
1060         KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
1061 #endif
1062         KFW_AFS_destroy_tickets_for_principal(uname);
1063     }
1064
1065     if (code) {
1066         char msg[128];
1067         HANDLE h;
1068         char *ptbuf[1];
1069
1070         StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
1071
1072         if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
1073             MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
1074
1075         h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
1076         ptbuf[0] = msg;
1077         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
1078                      1, 0, ptbuf, NULL);
1079         DeregisterEventSource(h);
1080             
1081         code = MapAuthError(code);
1082         SetLastError(code);
1083
1084         if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
1085         {
1086             if (*lpLogonScript)
1087                 LocalFree(*lpLogonScript);
1088             *lpLogonScript = NULL;
1089             if (!afsWillAutoStart)      // its not running, so if not autostart or integrated logon then just skip
1090                 code = 0;
1091         }
1092     }
1093
1094     if (opt.theseCells) free(opt.theseCells);
1095     if (opt.smbName) free(opt.smbName);
1096     if (opt.realm) free(opt.realm);
1097
1098     DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
1099     return code;
1100 }       
1101
1102 DWORD APIENTRY NPPasswordChangeNotify(
1103         LPCWSTR lpAuthentInfoType,
1104         LPVOID lpAuthentInfo,
1105         LPCWSTR lpPreviousAuthentInfoType,
1106         LPVOID lpPreviousAuthentInfo,
1107         LPWSTR lpStationName,
1108         LPVOID StationHandle,
1109         DWORD dwChangeInfo)
1110 {
1111     BOOLEAN interactive;
1112
1113     /* Are we interactive? */
1114     interactive = (wcsicmp(lpStationName, L"WinSta0") == 0);
1115
1116     /* Do not do anything if the logon session is not interactive. */
1117     if (!interactive)
1118         return 0;
1119
1120     /* Make sure the AFS Libraries are initialized */
1121     AfsLogonInit();
1122
1123     DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
1124     return 0;
1125 }
1126
1127 #include <userenv.h>
1128 #include <Winwlx.h>
1129 #include <afs/vice.h>
1130 #include <afs/fs_utils.h>
1131
1132 BOOL IsPathInAfs(const CHAR *strPath)
1133 {
1134     char space[2048];
1135     struct ViceIoctl blob;
1136     int code;
1137
1138     blob.in_size = 0;
1139     blob.out_size = 2048;
1140     blob.out = space;
1141
1142     code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
1143     if (code)
1144         return FALSE;
1145     return TRUE;
1146 }
1147
1148 #ifdef COMMENT
1149 typedef struct _WLX_NOTIFICATION_INFO {  
1150     ULONG Size;  
1151     ULONG Flags;  
1152     PWSTR UserName;  
1153     PWSTR Domain;  
1154     PWSTR WindowStation;  
1155     HANDLE hToken;  
1156     HDESK hDesktop;  
1157     PFNMSGECALLBACK pStatusCallback;
1158 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
1159 #endif
1160
1161 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
1162 {
1163     DWORD LSPtype, LSPsize;
1164     HKEY NPKey;
1165
1166     /* Make sure the AFS Libraries are initialized */
1167     AfsLogonInit();
1168
1169     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1170                         0, KEY_QUERY_VALUE, &NPKey);
1171     LSPsize=sizeof(TraceOption);
1172     RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
1173                      &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
1174
1175     RegCloseKey (NPKey);
1176     DebugEvent0("AFS_Startup_Event");
1177 }
1178
1179 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
1180 {
1181     DWORD code;
1182     TCHAR profileDir[1024] = TEXT("");
1183     DWORD  len = 1024;
1184     PTOKEN_USER  tokenUser = NULL;
1185     DWORD  retLen;
1186     DWORD LSPtype, LSPsize;
1187     HKEY NPKey;
1188     DWORD LogoffPreserveTokens = 0;
1189     LogonOptions_t opt;
1190
1191     /* Make sure the AFS Libraries are initialized */
1192     AfsLogonInit();
1193
1194     DebugEvent0("AFS_Logoff_Event - Start");
1195
1196     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1197                          0, KEY_QUERY_VALUE, &NPKey);
1198     LSPsize=sizeof(LogoffPreserveTokens);
1199     RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
1200                      &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
1201     RegCloseKey (NPKey);
1202
1203     if (!LogoffPreserveTokens) {
1204         memset(&opt, 0, sizeof(LogonOptions_t));
1205
1206         if (pInfo->UserName && pInfo->Domain) {
1207             char username[MAX_USERNAME_LENGTH] = "";
1208             char domain[MAX_DOMAIN_LENGTH] = "";
1209             size_t szlen = 0;
1210
1211             StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1212             WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1213                                  username, sizeof(username), NULL, NULL);
1214
1215             StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1216             WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1217                                  domain, sizeof(domain), NULL, NULL);
1218
1219             GetDomainLogonOptions(NULL, username, domain, &opt);
1220         }
1221
1222         if (ISREMOTE(opt.flags)) {
1223             if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1224             {
1225                 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1226                     tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1227
1228                     if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1229                     {
1230                         DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1231                     }
1232                 }
1233             }
1234
1235             /* We can't use pInfo->Domain for the domain since in the cross realm case 
1236              * this is source domain and not the destination domain.
1237              */
1238             if (tokenUser && QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1239                 WCHAR Domain[64]=L"";
1240                 GetLocalShortDomain(Domain, sizeof(Domain));
1241                 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1242                     if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1243                         GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1244                 }
1245             }
1246
1247             if (strlen(profileDir)) {
1248                 DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1249                 if (!IsPathInAfs(profileDir)) {
1250                     if (code = ktc_ForgetAllTokens())
1251                         DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1252                     else
1253                         DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1254                 } else {
1255                     DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1256                 }
1257             } else {
1258                 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1259             }
1260
1261             if ( tokenUser )
1262                 LocalFree(tokenUser);
1263         } else {
1264             DebugEvent0("AFS_Logoff_Event - Local Logon");
1265             if (code = ktc_ForgetAllTokens())
1266                 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1267             else
1268                 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1269         }
1270     } else {
1271         DebugEvent0("AFS_Logoff_Event - Preserving Tokens");
1272     }
1273
1274     DebugEvent0("AFS_Logoff_Event - End");
1275 }   
1276
1277 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1278 {
1279     TCHAR profileDir[1024] = TEXT("");
1280     DWORD  len = 1024;
1281     PTOKEN_USER  tokenUser = NULL;
1282     DWORD  retLen;
1283     WCHAR szUserW[128] = L"";
1284     char  szUserA[128] = "";
1285     char  szClient[MAX_PATH];
1286     char szPath[MAX_PATH] = "";
1287     NETRESOURCE nr;
1288     DWORD res;
1289     DWORD dwSize;
1290     LogonOptions_t opt;
1291
1292     /* Make sure the AFS Libraries are initialized */
1293     AfsLogonInit();
1294
1295     DebugEvent0("AFS_Logon_Event - Start");
1296
1297     DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1298
1299     memset(&opt, 0, sizeof(LogonOptions_t));
1300
1301     if (pInfo->UserName && pInfo->Domain) {
1302         char username[MAX_USERNAME_LENGTH] = "";
1303         char domain[MAX_DOMAIN_LENGTH] = "";
1304         size_t szlen = 0;
1305
1306         DebugEvent0("AFS_Logon_Event - pInfo UserName and Domain");
1307
1308         StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1309         WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1310                             username, sizeof(username), NULL, NULL);
1311         
1312         StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1313         WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1314                             domain, sizeof(domain), NULL, NULL);
1315
1316         DebugEvent0("AFS_Logon_Event - Calling GetDomainLogonOptions");
1317         GetDomainLogonOptions(NULL, username, domain, &opt);
1318     } else {
1319         if (!pInfo->UserName)
1320             DebugEvent0("AFS_Logon_Event - No pInfo->UserName");
1321         if (!pInfo->Domain)
1322             DebugEvent0("AFS_Logon_Event - No pInfo->Domain");
1323     }
1324
1325     DebugEvent("AFS_Logon_Event - opt.LogonOption = %lX opt.flags = %lX", 
1326                 opt.LogonOption, opt.flags);
1327
1328     if (!ISLOGONINTEGRATED(opt.LogonOption) || !ISREMOTE(opt.flags)) {
1329         DebugEvent0("AFS_Logon_Event - Logon is not integrated or not remote");
1330         goto done_logon_event;
1331     }
1332
1333     DebugEvent0("AFS_Logon_Event - Calling GetTokenInformation");
1334
1335     if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1336     {
1337         if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1338             tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1339
1340             if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1341             {
1342                 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1343             }
1344         }
1345     }
1346
1347     /* We can't use pInfo->Domain for the domain since in the cross realm case 
1348      * this is source domain and not the destination domain.
1349      */
1350     if (tokenUser && QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1351         WCHAR Domain[64]=L"";
1352         GetLocalShortDomain(Domain, sizeof(Domain));
1353         if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1354             if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1355                 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1356         }
1357     }
1358     
1359     if (strlen(profileDir)) {
1360         DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1361     } else {
1362         DebugEvent0("AFS_Logon_Event - Unable to load profile");
1363     }
1364
1365   done_logon_event:
1366     dwSize = sizeof(szUserA);
1367     if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1368         StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1369         WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1370     }
1371
1372     if (szUserA[0])
1373     {
1374         lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1375         StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1376
1377         DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1378
1379         memset (&nr, 0x00, sizeof(NETRESOURCE));
1380         nr.dwType=RESOURCETYPE_DISK;
1381         nr.lpLocalName=0;
1382         nr.lpRemoteName=szPath;
1383         res = WNetAddConnection2(&nr,NULL,szUserA,0);
1384         if (res)
1385             DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1386                         szPath, szUserA,res);
1387         else
1388             DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1389     } else 
1390         DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1391
1392     if ( tokenUser )
1393         LocalFree(tokenUser);
1394
1395     DebugEvent0("AFS_Logon_Event - End");
1396 }
1397
1398 static BOOL
1399 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1400 {
1401     NTSTATUS Status = 0;
1402     TOKEN_STATISTICS Stats;
1403     DWORD   ReqLen;
1404     BOOL    Success;
1405
1406     if (!ppSessionData)
1407         return FALSE;
1408     *ppSessionData = NULL;
1409
1410     Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1411     if ( !Success )
1412         return FALSE;
1413
1414     Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1415     if ( FAILED(Status) || !ppSessionData )
1416         return FALSE;
1417
1418     return TRUE;
1419 }
1420
1421 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1422 {
1423 #ifdef KFW_LOGON
1424     WCHAR szUserW[128] = L"";
1425     char  szUserA[128] = "";
1426     char szPath[MAX_PATH] = "";
1427     char szLogonId[128] = "";
1428     DWORD count;
1429     char filename[MAX_PATH] = "";
1430     char newfilename[MAX_PATH] = "";
1431     char commandline[MAX_PATH+256] = "";
1432     STARTUPINFO startupinfo;
1433     PROCESS_INFORMATION procinfo;
1434     HANDLE hf = INVALID_HANDLE_VALUE;
1435
1436     LUID LogonId = {0, 0};
1437     PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1438
1439     HKEY hKey1 = NULL, hKey2 = NULL;
1440
1441     /* Make sure the KFW Libraries are initialized */
1442     AfsLogonInit();
1443
1444     DebugEvent0("KFW_Logon_Event - Start");
1445
1446     GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1447
1448     if ( pLogonSessionData ) {
1449         LogonId = pLogonSessionData->LogonId;
1450         DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1451
1452         sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1453         LsaFreeReturnBuffer( pLogonSessionData );
1454     } else {
1455         DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1456         return;
1457     }
1458
1459     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1460     if ( count > sizeof(filename) || count == 0 ) {
1461         GetWindowsDirectory(filename, sizeof(filename));
1462     }
1463
1464     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1465     if ( count > sizeof(filename) || count == 0 ) {
1466         GetWindowsDirectory(filename, sizeof(filename));
1467     }
1468
1469     if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) {
1470         DebugEvent0("KFW_Logon_Event - filename too long");
1471         return;
1472     }
1473
1474     strcat(filename, "\\");
1475     strcat(filename, szLogonId);    
1476
1477     hf = CreateFile(filename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING, 
1478                      FILE_ATTRIBUTE_NORMAL, NULL);
1479     if (hf == INVALID_HANDLE_VALUE) {
1480         DebugEvent0("KFW_Logon_Event - file cannot be opened");
1481         return;
1482     }
1483     CloseHandle(hf);
1484  
1485     if (KFW_AFS_set_file_cache_dacl(filename, pInfo->hToken)) {
1486         DebugEvent0("KFW_Logon_Event - unable to set dacl");
1487         DeleteFile(filename);
1488         return;
1489     }
1490  
1491     if (KFW_AFS_obtain_user_temp_directory(pInfo->hToken, newfilename, sizeof(newfilename))) {
1492         DebugEvent0("KFW_Logon_Event - unable to obtain temp directory");
1493         return;
1494     }
1495
1496     if ( strlen(newfilename) + strlen(szLogonId) + 2 > sizeof(newfilename) ) {
1497         DebugEvent0("KFW_Logon_Event - new filename too long");
1498         return;
1499     }
1500
1501     strcat(newfilename, "\\");
1502     strcat(newfilename, szLogonId);    
1503
1504     if (!MoveFileEx(filename, newfilename, 
1505                      MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
1506         DebugEvent("KFW_Logon_Event - MoveFileEx failed GLE = 0x%x", GetLastError());
1507         return;
1508     }
1509
1510     sprintf(commandline, "afscpcc.exe \"%s\"", newfilename);
1511
1512     GetStartupInfo(&startupinfo);
1513     if (CreateProcessAsUser( pInfo->hToken,
1514                              "afscpcc.exe",
1515                              commandline,
1516                              NULL,
1517                              NULL,
1518                              FALSE,
1519                              CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1520                              NULL,
1521                              NULL,
1522                              &startupinfo,
1523                              &procinfo)) 
1524     {
1525         DebugEvent("KFW_Logon_Event - CommandLine %s", commandline);
1526
1527         WaitForSingleObject(procinfo.hProcess, 30000);
1528
1529         CloseHandle(procinfo.hThread);
1530         CloseHandle(procinfo.hProcess);
1531     } else {
1532         DebugEvent0("KFW_Logon_Event - CreateProcessFailed");
1533     }
1534
1535     DeleteFile(filename);
1536
1537     DebugEvent0("KFW_Logon_Event - End");
1538 #endif
1539 }
1540