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