windows-afslogon-pr_end-20060702
[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 for [%s]", effDomain);
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     else
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     UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
754     UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
755     UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
756
757     /* Make sure AD-DOMANS sent from login that is sent to us is striped */
758     ctemp = strchr(uname, '@');
759     if (ctemp) *ctemp = 0;
760
761     /* is the name all lowercase? */
762     for ( ctemp = uname; *ctemp ; ctemp++) {
763         if ( !islower(*ctemp) ) {
764             lowercased_name = FALSE;
765             break;
766         }
767     }
768
769     /*
770      * Get Logon options
771      */
772
773     GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
774     retryInterval = opt.retryInterval;
775     sleepInterval = opt.sleepInterval;
776     *lpLogonScript = opt.logonScript;
777
778     if (retryInterval < sleepInterval)
779         sleepInterval = retryInterval;
780
781     DebugEvent("Got logon script: %S",opt.logonScript);
782
783     afsWillAutoStart = AFSWillAutoStart();
784
785     DebugEvent("LogonOption[%x], Service AutoStart[%d]",
786                 opt.LogonOption,afsWillAutoStart);
787     
788     /* Check for zero length password if integrated logon*/
789     if ( ISLOGONINTEGRATED(opt.LogonOption) )  {
790         if ( password[0] == 0 ) {
791             DebugEvent("Password is the empty string");
792             code = GT_PW_NULL;
793             reason = "zero length password is illegal";
794             code=0;
795         }
796
797         /* Get cell name if doing integrated logon.  
798            We might overwrite this if we are logging into an AD realm and we find out that
799            the user's home dir is in some other cell. */
800         DebugEvent("About to call cm_GetRootCellName(%s)",cell);
801         code = cm_GetRootCellName(cell);
802         if (code < 0) { 
803             DebugEvent("Unable to obtain Root Cell");
804             code = KTC_NOCELL;
805             reason = "unknown cell";
806             code=0;
807         } else {
808             DebugEvent("Cell is %s",cell);
809         }       
810
811         /* We get the user's home directory path, if applicable, though we can't lookup the
812            cell right away because the client service may not have started yet. This call
813            also sets the AD_REALM flag in opt.flags if applicable. */
814         if (ISREMOTE(opt.flags)) {
815             DebugEvent("Is Remote");
816             GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
817         }
818     }
819
820     /* loop until AFS is started. */
821     if (afsWillAutoStart) {
822         while (IsServiceRunning() || IsServiceStartPending()) {
823             DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
824                         opt.LogonOption,afsWillAutoStart);
825
826             if (ISADREALM(opt.flags)) {
827                 code = GetFileCellName(homePath,cell,256);
828                 if (!code) {
829                     DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
830                 }
831                 /* Don't bail out if GetFileCellName failed.
832                  * The home dir may not be in AFS after all. 
833                  */
834             } else
835                 code=0;
836                 
837             /* if Integrated Logon  */
838             if (ISLOGONINTEGRATED(opt.LogonOption))
839             {                   
840                 if ( KFW_is_available() ) {
841                     code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
842                     DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
843                                 uname,opt.smbName,cell,code);
844                     if (code == 0 && opt.theseCells) { 
845                         char * principal, *p;
846                         size_t len, tlen;
847
848                         StringCchLength(cell, MAX_DOMAIN_LENGTH, &tlen);
849                         len = tlen;
850                         StringCchLength(uname, MAX_USERNAME_LENGTH, &tlen);
851                         len += tlen + 2;
852
853                         /* tlen is now the length of uname in characters */
854                         principal = (char *)malloc(len * sizeof(char));
855                         if ( principal ) {
856                             StringCchCopy(principal, len, uname);
857                             p = principal + tlen;
858                             *p++ = '@';
859                             StringCchCopy(p, len - tlen - 1, cell);
860                             for ( ;*p; p++) {
861                                 *p = toupper(*p);
862                             }
863
864                             p = opt.theseCells;
865                             while ( *p ) {
866                                 code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
867                                 DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
868                                             principal,opt.smbName,p,code2);
869                                 p += strlen(p) + 1;
870                             }
871                             free(principal);
872                         }
873                     }
874                 } else {
875                     code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
876                                                         uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
877                                                         &reason);
878                     DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2 Code[%x] uname[%s] smbname=[%s] Cell[%s] PwExp=[%d] Reason=[%s]",
879                                 code,uname,opt.smbName,cell,pw_exp,reason?reason:"");
880                 }       
881                 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
882                     for ( ctemp = uname; *ctemp ; ctemp++) {
883                         *ctemp = tolower(*ctemp);
884                     }
885                     lowercased_name = TRUE;
886                     goto sleeping;
887                 }
888
889                 /* is service started yet?*/
890
891                 /* If we've failed because the client isn't running yet and the
892                  * client is set to autostart (and therefore it makes sense for
893                  * us to wait for it to start) then sleep a while and try again. 
894                  * If the error was something else, then give up. */
895                 if (code != KTC_NOCM && code != KTC_NOCMRPC)
896                     break;
897             }
898             else {  
899                 /*JUST check to see if its running*/
900                 if (IsServiceRunning())
901                     break;
902                 if (!IsServiceStartPending()) {
903                     code = KTC_NOCMRPC;
904                     reason = "AFS Service start failed";
905                     break;
906                 }
907             }
908
909             /* If the retry interval has expired and we still aren't
910              * logged in, then just give up if we are not in interactive
911              * mode or the failSilently flag is set, otherwise let the
912              * user know we failed and give them a chance to try again. */
913             if (retryInterval <= 0) {
914                 reason = "AFS not running";
915                 if (!interactive || opt.failSilently)
916                     break;
917                 flag = MessageBox(hwndOwner,
918                                    "AFS is still starting.  Retry?",
919                                    "AFS Logon",
920                                    MB_ICONQUESTION | MB_RETRYCANCEL);
921                 if (flag == IDCANCEL)
922                     break;
923
924                 /* Wait just a little while and try again */
925                 retryInterval = opt.retryInterval;
926             }
927
928           sleeping:
929             Sleep(sleepInterval * 1000);
930             retryInterval -= sleepInterval;
931         }
932     }
933     DebugEvent("while loop exited");
934     /* remove any kerberos 5 tickets currently held by the SYSTEM account
935      * for this user 
936      */
937     if (ISLOGONINTEGRATED(opt.LogonOption) && KFW_is_available()) {
938         sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
939         KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
940
941         KFW_AFS_destroy_tickets_for_principal(uname);
942     }
943
944     if (code) {
945         char msg[128];
946         HANDLE h;
947         char *ptbuf[1];
948
949         StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
950
951         if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
952             MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
953
954         h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
955         ptbuf[0] = msg;
956         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
957                      1, 0, ptbuf, NULL);
958         DeregisterEventSource(h);
959             
960         code = MapAuthError(code);
961         SetLastError(code);
962
963         if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
964         {
965             if (*lpLogonScript)
966                 LocalFree(*lpLogonScript);
967             *lpLogonScript = NULL;
968             if (!afsWillAutoStart)      // its not running, so if not autostart or integrated logon then just skip
969                 code = 0;
970         }
971     }
972
973     if (opt.theseCells) free(opt.theseCells);
974     if (opt.smbName) free(opt.smbName);
975
976     DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
977     return code;
978 }       
979
980 DWORD APIENTRY NPPasswordChangeNotify(
981         LPCWSTR lpAuthentInfoType,
982         LPVOID lpAuthentInfo,
983         LPCWSTR lpPreviousAuthentInfoType,
984         LPVOID lpPreviousAuthentInfo,
985         LPWSTR lpStationName,
986         LPVOID StationHandle,
987         DWORD dwChangeInfo)
988 {
989     /* Make sure the AFS Libraries are initialized */
990     AfsLogonInit();
991
992     DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
993     return 0;
994 }
995
996 #include <userenv.h>
997 #include <Winwlx.h>
998 #include <afs/vice.h>
999 #include <afs/fs_utils.h>
1000
1001 BOOL IsPathInAfs(const CHAR *strPath)
1002 {
1003     char space[2048];
1004     struct ViceIoctl blob;
1005     int code;
1006
1007     blob.in_size = 0;
1008     blob.out_size = 2048;
1009     blob.out = space;
1010
1011     code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
1012     if (code)
1013         return FALSE;
1014     return TRUE;
1015 }
1016
1017 #ifdef COMMENT
1018 typedef struct _WLX_NOTIFICATION_INFO {  
1019     ULONG Size;  
1020     ULONG Flags;  
1021     PWSTR UserName;  
1022     PWSTR Domain;  
1023     PWSTR WindowStation;  
1024     HANDLE hToken;  
1025     HDESK hDesktop;  
1026     PFNMSGECALLBACK pStatusCallback;
1027 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
1028 #endif
1029
1030 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
1031 {
1032     DWORD LSPtype, LSPsize;
1033     HKEY NPKey;
1034
1035     /* Make sure the AFS Libraries are initialized */
1036     AfsLogonInit();
1037
1038     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1039                         0, KEY_QUERY_VALUE, &NPKey);
1040     LSPsize=sizeof(TraceOption);
1041     RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
1042                      &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
1043
1044     RegCloseKey (NPKey);
1045     DebugEvent0("AFS_Startup_Event");
1046 }
1047
1048 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
1049 {
1050     DWORD code;
1051     TCHAR profileDir[1024] = TEXT("");
1052     DWORD  len = 1024;
1053     PTOKEN_USER  tokenUser = NULL;
1054     DWORD  retLen;
1055     DWORD LSPtype, LSPsize;
1056     HKEY NPKey;
1057     DWORD LogoffPreserveTokens = 0;
1058     LogonOptions_t opt;
1059
1060     /* Make sure the AFS Libraries are initialized */
1061     AfsLogonInit();
1062
1063     DebugEvent0("AFS_Logoff_Event - Start");
1064
1065     (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1066                          0, KEY_QUERY_VALUE, &NPKey);
1067     LSPsize=sizeof(LogoffPreserveTokens);
1068     RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
1069                      &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
1070     RegCloseKey (NPKey);
1071
1072     if (!LogoffPreserveTokens) {
1073         memset(&opt, 0, sizeof(LogonOptions_t));
1074
1075         if (pInfo->UserName && pInfo->Domain) {
1076             char username[MAX_USERNAME_LENGTH] = "";
1077             char domain[MAX_DOMAIN_LENGTH] = "";
1078             size_t szlen = 0;
1079
1080             StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1081             WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1082                                  username, sizeof(username), NULL, NULL);
1083
1084             StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1085             WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1086                                  domain, sizeof(domain), NULL, NULL);
1087
1088             GetDomainLogonOptions(NULL, username, domain, &opt);
1089         }
1090
1091         if (ISREMOTE(opt.flags)) {
1092             if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1093             {
1094                 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1095                     tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1096
1097                     if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1098                     {
1099                         DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1100                     }
1101                 }
1102             }
1103
1104             /* We can't use pInfo->Domain for the domain since in the cross realm case 
1105              * this is source domain and not the destination domain.
1106              */
1107             if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1108                 WCHAR Domain[64]=L"";
1109                 GetLocalShortDomain(Domain, sizeof(Domain));
1110                 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1111                     if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1112                         GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1113                 }
1114             }
1115
1116             if (strlen(profileDir)) {
1117                 DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1118                 if (!IsPathInAfs(profileDir)) {
1119                     if (code = ktc_ForgetAllTokens())
1120                         DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1121                     else
1122                         DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1123                 } else {
1124                     DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1125                 }
1126             } else {
1127                 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1128             }
1129
1130             if ( tokenUser )
1131                 LocalFree(tokenUser);
1132         } else {
1133             DebugEvent0("AFS_Logoff_Event - Local Logon");
1134             if (code = ktc_ForgetAllTokens())
1135                 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1136             else
1137                 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1138         }
1139     } else {
1140         DebugEvent0("AFS_Logoff_Event - Preserving Tokens");
1141     }
1142
1143     DebugEvent0("AFS_Logoff_Event - End");
1144 }   
1145
1146 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1147 {
1148     TCHAR profileDir[1024] = TEXT("");
1149     DWORD  len = 1024;
1150     PTOKEN_USER  tokenUser = NULL;
1151     DWORD  retLen;
1152     WCHAR szUserW[128] = L"";
1153     char  szUserA[128] = "";
1154     char  szClient[MAX_PATH];
1155     char szPath[MAX_PATH] = "";
1156     NETRESOURCE nr;
1157     DWORD res;
1158     DWORD dwSize;
1159     LogonOptions_t opt;
1160
1161     /* Make sure the AFS Libraries are initialized */
1162     AfsLogonInit();
1163
1164     DebugEvent0("AFS_Logon_Event - Start");
1165
1166     DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1167
1168     memset(&opt, 0, sizeof(LogonOptions_t));
1169
1170     if (pInfo->UserName && pInfo->Domain) {
1171         char username[MAX_USERNAME_LENGTH] = "";
1172         char domain[MAX_DOMAIN_LENGTH] = "";
1173         size_t szlen = 0;
1174
1175         DebugEvent0("AFS_Logon_Event - pInfo UserName and Domain");
1176
1177         StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1178         WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1179                             username, sizeof(username), NULL, NULL);
1180         
1181         StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1182         WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1183                             domain, sizeof(domain), NULL, NULL);
1184
1185         DebugEvent0("AFS_Logon_Event - Calling GetDomainLogonOptions");
1186         GetDomainLogonOptions(NULL, username, domain, &opt);
1187     } else {
1188         if (!pInfo->UserName)
1189             DebugEvent0("AFS_Logon_Event - No pInfo->UserName");
1190         if (!pInfo->Domain)
1191             DebugEvent0("AFS_Logon_Event - No pInfo->Domain");
1192     }
1193
1194     DebugEvent("AFS_Logon_Event - opt.LogonOption = %lX opt.flags = %lX", 
1195                 opt.LogonOption, opt.flags);
1196
1197     if (!ISLOGONINTEGRATED(opt.LogonOption) || !ISREMOTE(opt.flags)) {
1198         DebugEvent0("AFS_Logon_Event - Logon is not integrated or not remote");
1199         goto done_logon_event;
1200     }
1201
1202     DebugEvent0("AFS_Logon_Event - Calling GetTokenInformation");
1203
1204     if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1205     {
1206         if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1207             tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1208
1209             if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1210             {
1211                 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1212             }
1213         }
1214     }
1215
1216     /* We can't use pInfo->Domain for the domain since in the cross realm case 
1217      * this is source domain and not the destination domain.
1218      */
1219     if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1220         WCHAR Domain[64]=L"";
1221         GetLocalShortDomain(Domain, sizeof(Domain));
1222         if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1223             if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1224                 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1225         }
1226     }
1227     
1228     if (strlen(profileDir)) {
1229         DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1230     } else {
1231         DebugEvent0("AFS_Logon_Event - Unable to load profile");
1232     }
1233
1234   done_logon_event:
1235     dwSize = sizeof(szUserA);
1236     if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1237         StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1238         WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1239     }
1240
1241     if (szUserA[0])
1242     {
1243         lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1244         StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1245
1246         DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1247
1248         memset (&nr, 0x00, sizeof(NETRESOURCE));
1249         nr.dwType=RESOURCETYPE_DISK;
1250         nr.lpLocalName=0;
1251         nr.lpRemoteName=szPath;
1252         res = WNetAddConnection2(&nr,NULL,szUserA,0);
1253         if (res)
1254             DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1255                         szPath, szUserA,res);
1256         else
1257             DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1258     } else 
1259         DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1260
1261     if ( tokenUser )
1262         LocalFree(tokenUser);
1263
1264     DebugEvent0("AFS_Logon_Event - End");
1265 }
1266
1267 static BOOL
1268 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1269 {
1270     NTSTATUS Status = 0;
1271     TOKEN_STATISTICS Stats;
1272     DWORD   ReqLen;
1273     BOOL    Success;
1274
1275     if (!ppSessionData)
1276         return FALSE;
1277     *ppSessionData = NULL;
1278
1279     Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1280     if ( !Success )
1281         return FALSE;
1282
1283     Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1284     if ( FAILED(Status) || !ppSessionData )
1285         return FALSE;
1286
1287     return TRUE;
1288 }
1289
1290 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1291 {
1292     WCHAR szUserW[128] = L"";
1293     char  szUserA[128] = "";
1294     char szPath[MAX_PATH] = "";
1295     char szLogonId[128] = "";
1296     DWORD count;
1297     char filename[256];
1298     char commandline[512];
1299     STARTUPINFO startupinfo;
1300     PROCESS_INFORMATION procinfo;
1301
1302     LUID LogonId = {0, 0};
1303     PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1304
1305     HKEY hKey1 = NULL, hKey2 = NULL;
1306
1307     /* Make sure the KFW Libraries are initialized */
1308     AfsLogonInit();
1309
1310     DebugEvent0("KFW_Logon_Event - Start");
1311
1312     GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1313
1314     if ( pLogonSessionData ) {
1315         LogonId = pLogonSessionData->LogonId;
1316         DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1317
1318         sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1319         LsaFreeReturnBuffer( pLogonSessionData );
1320     } else {
1321         DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1322         return;
1323     }
1324
1325     count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1326     if ( count > sizeof(filename) || count == 0 ) {
1327         GetWindowsDirectory(filename, sizeof(filename));
1328     }
1329
1330     if ( strlen(filename) + strlen(szLogonId) + 2 <= sizeof(filename) ) {
1331         strcat(filename, "\\");
1332         strcat(filename, szLogonId);    
1333
1334         sprintf(commandline, "afscpcc.exe \"%s\"", filename);
1335
1336         GetStartupInfo(&startupinfo);
1337         if (CreateProcessAsUser( pInfo->hToken,
1338                              "afscpcc.exe",
1339                              commandline,
1340                              NULL,
1341                              NULL,
1342                              FALSE,
1343                              CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1344                              NULL,
1345                              NULL,
1346                              &startupinfo,
1347                              &procinfo)) 
1348         {
1349             WaitForSingleObject(procinfo.hProcess, 30000);
1350
1351             CloseHandle(procinfo.hThread);
1352             CloseHandle(procinfo.hProcess);
1353         }
1354     }
1355
1356     DeleteFile(filename);
1357
1358     DebugEvent0("KFW_Logon_Event - End");
1359 }
1360