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