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