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