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