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