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