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