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