2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 #include <sys/types.h>
21 #define SECURITY_WIN32
30 #include <afs/pioctl_nt.h>
31 #include <afs/kautils.h>
34 #include "cm_config.h"
37 #include "lanahelper.h"
39 /* Allocated in Windows Driver Kit */
40 #ifndef WNNC_NET_OPENAFS
41 #define WNNC_NET_OPENAFS 0x00390000
44 #include <WINNT\afsreg.h>
46 DWORD TraceOption = 0;
51 #define AFS_LOGON_EVENT_NAME TEXT("AFS Logon")
53 void DebugEvent0(char *a)
55 HANDLE h; char *ptbuf[1];
57 if (!Debug && !ISLOGONTRACE(TraceOption))
62 OutputDebugString("\r\n");
65 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
66 if (h != INVALID_HANDLE_VALUE) {
68 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 1008, NULL, 1, 0, (const char **)ptbuf, NULL);
69 DeregisterEventSource(h);
74 void DebugEvent(char *b,...)
77 char *ptbuf[1], buf[MAXBUF_+1];
80 if (!Debug && !ISLOGONTRACE(TraceOption))
84 StringCbVPrintf(buf, MAXBUF_+1,b,marker);
88 OutputDebugString(buf);
89 OutputDebugString("\r\n");
92 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
93 if (h != INVALID_HANDLE_VALUE) {
95 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 1008, NULL, 1, 0, (const char **)ptbuf, NULL);
96 DeregisterEventSource(h);
101 static HANDLE hInitMutex = NULL;
102 static BOOL bInit = FALSE;
104 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
110 case DLL_PROCESS_ATTACH:
111 /* Initialization Mutex */
113 hInitMutex = CreateMutex(NULL, FALSE, NULL);
115 WSAStartup( MAKEWORD(2,2), &wsaData );
118 case DLL_PROCESS_DETACH:
120 CloseHandle(hInitMutex);
125 case DLL_THREAD_ATTACH:
126 case DLL_THREAD_DETACH:
128 /* Everything else succeeds but does nothing. */
135 void AfsLogonInit(void)
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
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?
154 * We only need this if we are not using KFW.
156 if (!KFW_is_available())
160 ReleaseMutex(hInitMutex);
164 CHAR *GenRandomName(CHAR *pbuf)
167 srand( (unsigned)time( NULL ) );
168 for (i=0;i<MAXRANDOMNAMELEN-1;i++)
169 pbuf[i]='a'+(rand() % 26);
170 pbuf[MAXRANDOMNAMELEN-1]=0;
174 BOOLEAN AFSWillAutoStart(void)
179 BOOLEAN result = FALSE;
180 LPQUERY_SERVICE_CONFIG pConfig = NULL;
184 /* Open services manager */
185 scm = OpenSCManager(NULL, NULL, GENERIC_READ);
186 if (!scm) return FALSE;
188 /* Open AFSD service */
189 svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
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)
200 /* Allocate buffer */
201 pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
205 /* Query AFSD service config, this time for real */
206 flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
210 /* Is it autostart? */
211 if (pConfig->dwStartType < SERVICE_DEMAND_START)
217 CloseServiceHandle(svc);
219 CloseServiceHandle(scm);
224 DWORD MapAuthError(DWORD 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.
231 * Instead return WN_NET_ERROR (ERROR_UNEXP_NET_ERR) to indicate a
232 * problem with this network.
243 DWORD APIENTRY NPGetCaps(DWORD index)
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.
256 case WNNC_SPEC_VERSION:
257 return WNNC_SPEC_VERSION51;
260 /* Say we are already started, even though we might wait after we receive NPLogonNotify */
269 NetUserGetProfilePath( LPCWSTR Domain, LPCWSTR UserName, char * profilePath,
270 DWORD profilePathLen )
273 LPWSTR ServerName = NULL;
274 LPUSER_INFO_3 p3 = NULL;
276 NetGetAnyDCName(NULL, Domain, (LPBYTE *)&ServerName);
277 /* if NetGetAnyDCName fails, ServerName == NULL
278 * NetUserGetInfo will obtain local user information
280 code = NetUserGetInfo(ServerName, UserName, 3, (LPBYTE *)&p3);
281 if (code == NERR_Success)
283 code = NERR_UserNotFound;
285 if (p3->usri3_profile) {
286 DWORD len = lstrlenW(p3->usri3_profile);
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';
295 NetApiBufferFree(p3);
299 NetApiBufferFree(ServerName);
303 BOOL IsServiceRunning (void)
305 SERVICE_STATUS Status;
307 memset (&Status, 0x00, sizeof(Status));
308 Status.dwCurrentState = SERVICE_STOPPED;
310 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
313 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
315 QueryServiceStatus (hService, &Status);
316 CloseServiceHandle (hService);
319 CloseServiceHandle (hManager);
321 DebugEvent("AFS AfsLogon - Test Service Running Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
322 return (Status.dwCurrentState == SERVICE_RUNNING);
325 BOOL IsServiceStartPending (void)
327 SERVICE_STATUS Status;
329 memset (&Status, 0x00, sizeof(Status));
330 Status.dwCurrentState = SERVICE_STOPPED;
332 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
335 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
337 QueryServiceStatus (hService, &Status);
338 CloseServiceHandle (hService);
341 CloseServiceHandle (hManager);
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);
347 BOOL StartTheService (void)
352 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ|SERVICE_START)) != NULL)
355 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ|SERVICE_START)) != NULL)
357 StartService (hService, 0, NULL);
358 gle = GetLastError();
359 CloseServiceHandle (hService);
361 gle = GetLastError();
363 CloseServiceHandle (hManager);
365 DebugEvent("AFS AfsLogon - Service Start Return Code[0x%x]",gle);
370 FindFullDomainName(const char *short_domain)
373 * Possible sources of domain or realm information:
375 * HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\History
376 * MachineDomain REG_SZ
378 * HKLM\SYSTEM\CurrentControlSet\Control\Lsa\CachedMachineNames
379 * NameUserPrincipal REG_SZ MACHINE$@DOMAIN
381 * HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Domains\<DOMAIN>
389 size_t short_domain_len;
391 if (short_domain == NULL)
394 short_domain_len = strlen(short_domain);
396 /* First look for this machine's Active Directory domain */
397 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
398 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History",
400 if (rv == ERROR_SUCCESS) {
403 rv = RegQueryValueEx(hk, "MachineDomain", 0, &dwType, NULL, &dwSize);
404 if (rv == ERROR_SUCCESS && dwType == REG_SZ) {
405 domain = malloc(dwSize + 1);
408 rv = RegQueryValueEx(hk, "MachineDomain", 0, &dwType, domain, &dwSize);
409 if (rv == ERROR_SUCCESS && dwType == REG_SZ) {
410 domain[dwSize-1] = '\0';
411 if (strncmp(short_domain, domain, strlen(short_domain)) == 0 &&
412 domain[short_domain_len] == '.')
424 /* Then check the list of configured Kerberos realms, if any */
425 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
426 "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Group Policy\\History",
428 if (rv == ERROR_SUCCESS) {
432 for (index=0; rv==ERROR_SUCCESS; index++) {
434 rv = RegEnumKeyEx(hk, index, name, &cch, NULL, NULL, NULL, NULL);
435 if (rv == ERROR_SUCCESS &&
436 strncmp(short_domain, name, strlen(short_domain)) == 0 &&
437 name[short_domain_len] == '.') {
438 domain = strdup(name);
450 * LOOKUPKEYCHAIN: macro to look up the value in the list of keys in order until it's found
451 * v:variable to receive value (reference type).
453 * d:default, in case the value isn't on any of the keys
456 #define LOOKUPKEYCHAIN(v,t,d,n) \
458 rv = ~ERROR_SUCCESS; \
461 dwSize = sizeof(v); \
462 rv = RegQueryValueEx(hkUserMap, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
463 if(rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) \
464 DebugEvent(#v " found in hkUserMap with type [%d]", dwType); \
466 if(hkDom && ((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || dwType != t)) { \
467 dwSize = sizeof(v); \
468 rv = RegQueryValueEx(hkDom, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
469 if(rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) \
470 DebugEvent(#v " found in hkDom with type [%d]", dwType); \
472 if(hkDoms && ((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || dwType != t)) { \
473 dwSize = sizeof(v); \
474 rv = RegQueryValueEx(hkDoms, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
475 if(rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) \
476 DebugEvent(#v " found in hkDoms with type [%d]", dwType); \
478 if(hkNp && ((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || dwType != t)) { \
479 dwSize = sizeof(v); \
480 rv = RegQueryValueEx(hkNp, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
481 if(rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) \
482 DebugEvent(#v " found in hkNp with type [%d]", dwType); \
484 if((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || dwType != t) { \
486 DebugEvent0(#v " being set to default"); \
492 * FINDKEYCHAIN1: macro to find the value in the list of keys in order until it's found.
493 * Sets hkTemp variable to the key the value is found in.
497 #define FINDKEYCHAIN1(t,n) \
500 rv = ~ERROR_SUCCESS; \
504 rv = RegQueryValueEx(hkUserMap, n, 0, &dwType, NULL, &dwSize); \
505 if((rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) && dwType == t) { \
506 DebugEvent(#n " found in hkUserMap with type [%d]", dwType); \
507 hkTemp = hkUserMap; \
510 if(hkDom && ((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || dwType != t)) { \
512 rv = RegQueryValueEx(hkDom, n, 0, &dwType, NULL, &dwSize); \
513 if((rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) && dwType == t) { \
514 DebugEvent(#n " found in hkDom with type [%d]", dwType); \
518 if(hkDoms && ((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || dwType != t)) { \
520 rv = RegQueryValueEx(hkDoms, n, 0, &dwType, NULL, &dwSize); \
521 if((rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) && dwType == t) { \
522 DebugEvent(#n " found in hkDoms with type [%d]", dwType); \
526 if(hkNp && ((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || dwType != t)) { \
528 rv = RegQueryValueEx(hkNp, n, 0, &dwType, NULL, &dwSize); \
529 if((rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) && dwType == t) { \
530 DebugEvent(#n " found in hkNp with type [%d]", dwType); \
534 if((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || dwType != t) { \
535 DebugEvent0(#n " not found"); \
540 * FINDKEYCHAIN2: macro to find the value in the list of keys in order until it's found.
541 * Sets hkTemp variable to the key the value is found in.
546 #define FINDKEYCHAIN2(t1,t2,n) \
549 rv = ~ERROR_SUCCESS; \
553 rv = RegQueryValueEx(hkUserMap, n, 0, &dwType, NULL, &dwSize); \
554 if((rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) && (dwType == t1 || dwType == t2)) { \
555 DebugEvent(#n " found in hkUserMap with type [%d]", dwType); \
556 hkTemp = hkUserMap; \
559 if(hkDom && ((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || (dwType != t1 && dwType != t2))) { \
561 rv = RegQueryValueEx(hkDom, n, 0, &dwType, NULL, &dwSize); \
562 if((rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) && (dwType == t1 || dwType == t2)) {\
563 DebugEvent(#n " found in hkDom with type [%d]", dwType); \
567 if(hkDoms && ((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || (dwType != t1 && dwType != t2))) { \
569 rv = RegQueryValueEx(hkDoms, n, 0, &dwType, NULL, &dwSize); \
570 if((rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) && (dwType == t1 || dwType == t2)) { \
571 DebugEvent(#n " found in hkDoms with type [%d]", dwType); \
575 if(hkNp && ((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || (dwType != t1 && dwType != t2))) { \
577 rv = RegQueryValueEx(hkNp, n, 0, &dwType, NULL, &dwSize); \
578 if((rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) && (dwType == t1 || dwType == t2)) { \
579 DebugEvent(#n " found in hkNp with type [%d]", dwType); \
583 if((rv != ERROR_SUCCESS && rv != ERROR_MORE_DATA) || (dwType != t1 && dwType != t2)) { \
584 DebugEvent0(#n " not found"); \
590 * Get domain specific configuration info. We return void
591 * because if anything goes wrong we just return defaults.
594 GetDomainLogonOptions( PLUID lpLogonId, BOOLEAN bKerberos,
595 char * username, char * domain, LogonOptions_t *opt ) {
596 HKEY hkParm = NULL; /* Service parameter */
597 HKEY hkNp = NULL; /* network provider key */
598 HKEY hkDoms = NULL; /* domains key */
599 HKEY hkDom = NULL; /* DOMAINS/domain key */
600 HKEY hkUserMap = NULL; /* User mapping key */
606 char computerName[MAX_COMPUTERNAME_LENGTH + 1]="";
607 char *effDomain = NULL;
609 memset(opt, 0, sizeof(LogonOptions_t));
610 DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
612 /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name. */
613 opt->flags = LOGON_FLAG_REMOTE;
615 dwSize = MAX_COMPUTERNAME_LENGTH + 1;
616 if(GetComputerName(computerName, &dwSize)) {
617 if(!cm_stricmp_utf8(computerName, domain)) {
618 effDomain = "LOCALHOST";
619 opt->flags = LOGON_FLAG_LOCAL;
622 if (effDomain == NULL)
626 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, KEY_READ, &hkParm );
627 if(rv != ERROR_SUCCESS) {
629 DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
632 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PROVIDER_SUBKEY, 0, KEY_READ, &hkNp );
633 if(rv != ERROR_SUCCESS) {
635 DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
639 rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
640 if( rv != ERROR_SUCCESS ) {
642 DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
646 if(hkDoms && effDomain) {
647 rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
648 if( rv != ERROR_SUCCESS ) {
650 DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
652 /* If none of the domains match, we shouldn't use the domain key either */
656 rv = RegOpenKeyEx( hkDom, username, 0, KEY_READ, &hkUserMap);
657 if ( rv != ERROR_SUCCESS ) {
659 DebugEvent("GetDomainLogonOptions: Can't open usermap key for [%s]@[%s] [%d]",
660 username, effDomain, rv);
664 DebugEvent0("Not opening domain key");
668 * Most individual values can be specified on the user mapping key, the domain key,
669 * the domains key or in the net provider key. They fail over in that order.
670 * If none is found, we just use the defaults.
674 LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
676 /* FailLoginsSilently */
677 dwSize = sizeof(dwDummy);
678 rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
679 if (rv != ERROR_SUCCESS)
680 LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
681 opt->failSilently = dwDummy ? 1 :0;
684 LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
687 LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
689 if(!ISLOGONINTEGRATED(opt->LogonOption)) {
690 DebugEvent0("Integrated logon disabled");
691 goto cleanup; /* no need to lookup the logon script */
694 /* come up with SMB username */
696 /* username and domain for logon session is not necessarily the same as
697 username and domain passed into network provider. */
698 PSECURITY_LOGON_SESSION_DATA plsd=NULL;
699 char lsaUsername[MAX_USERNAME_LENGTH]="";
700 char lsaDomain[MAX_DOMAIN_LENGTH]="";
704 Status = LsaGetLogonSessionData(lpLogonId, &plsd);
705 if ( FAILED(Status) || plsd == NULL ) {
706 DebugEvent("LsaGetLogonSessionData failed [0x%x]", Status);
710 if (!UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH))
713 if (!UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH))
716 DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
718 if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
723 if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
730 opt->smbName = malloc(len);
731 if (opt->smbName == NULL)
734 StringCbCopy(opt->smbName, len, lsaDomain);
735 StringCbCat(opt->smbName, len, "\\");
736 StringCbCat(opt->smbName, len, lsaUsername);
738 strlwr(opt->smbName);
742 LsaFreeReturnBuffer(plsd);
745 if (opt->smbName == NULL) {
748 DebugEvent("Constructing username using [%s] and [%s]",
751 len = strlen(username) + strlen(domain) + 2;
753 opt->smbName = malloc(len);
754 if (opt->smbName == NULL)
757 StringCbCopy(opt->smbName, len, domain);
758 StringCbCat(opt->smbName, len, "\\");
759 StringCbCat(opt->smbName, len, username);
761 strlwr(opt->smbName);
764 DebugEvent0("Looking up logon script");
766 /* First find out where the key is */
767 FINDKEYCHAIN2(REG_SZ, REG_EXPAND_SZ, REG_CLIENT_LOGON_SCRIPT_PARM);
768 /* Note that the LogonScript in the NP key not used. */
773 WCHAR *regscript = NULL;
774 WCHAR *regexscript = NULL;
775 WCHAR *regexuscript = NULL;
776 WCHAR *wuname = NULL;
781 StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
784 wuname = malloc(len * sizeof(WCHAR));
786 goto doneLogonScript;
787 MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,(int)(len*sizeof(WCHAR)));
789 DebugEvent("Username is set for [%S]", wuname);
791 /* dwSize still has the size of the required buffer in bytes. */
792 regscript = malloc(dwSize);
794 goto doneLogonScript;
795 rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
796 if(rv != ERROR_SUCCESS) {/* what the ..? */
797 DebugEvent("Can't look up logon script rv [%d] size [%d] gle %d",rv, dwSize, GetLastError());
798 goto doneLogonScript;
801 DebugEvent("Found logon script [%S]", regscript);
803 if(dwType == REG_EXPAND_SZ) {
806 dwSize += MAX_PATH * sizeof(WCHAR); /* make room for environment expansion. */
807 regexscript = malloc(dwSize);
809 goto doneLogonScript;
810 dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
812 regscript = regexscript;
814 if(dwReq > (dwSize / sizeof(WCHAR))) {
815 DebugEvent0("Overflow while expanding environment strings.");
816 goto doneLogonScript;
820 DebugEvent("After expanding env strings [%S]", regscript);
822 if(wcsstr(regscript, L"%s")) {
823 dwSize += (DWORD)(len * sizeof(WCHAR)); /* make room for username expansion */
824 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
826 goto doneLogonScript;
827 hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
829 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
831 goto doneLogonScript;
832 hr = StringCbCopyW(regexuscript, dwSize, regscript);
835 DebugEvent("After expanding username [%S]", regexuscript);
838 opt->logonScript = regexuscript;
840 LocalFree(regexuscript);
843 if(wuname) free(wuname);
844 if(regscript) free(regscript);
845 if(regexscript) free(regexscript);
848 DebugEvent0("Looking up TheseCells");
850 /* First find out where the key is */
851 FINDKEYCHAIN1(REG_MULTI_SZ, REG_CLIENT_THESE_CELLS_PARM);
854 CHAR * thesecells = NULL, *p;
856 /* dwSize still has the size of the required buffer in bytes. */
857 thesecells = malloc(dwSize*2);
862 rv = RegQueryValueEx(hkTemp, REG_CLIENT_THESE_CELLS_PARM, 0, NULL, (LPBYTE) thesecells, &dwSize);
863 if(rv != ERROR_SUCCESS) {/* what the ..? */
864 DebugEvent("Can't look up TheseCells rv [%d] size [%d] gle [%d]",rv, dwSize, GetLastError());
868 /* TheseCells is a REG_MULTI_SZ */
869 if ( thesecells && thesecells[0]) {
870 for ( p=thesecells; *p; p += (strlen(p) + 1)) {
871 DebugEvent("Found TheseCells [%s]", p);
873 opt->theseCells = thesecells;
876 DebugEvent("TheseCells [REG_MULTI_SZ] not found");
880 if (thesecells) free(thesecells);
883 DebugEvent0("Looking up Realm");
885 /* First find out where the key is */
886 FINDKEYCHAIN1(REG_SZ, REG_CLIENT_REALM_PARM);
891 /* dwSize still has the size of the required buffer in bytes. */
892 realm = malloc(dwSize*2);
897 rv = RegQueryValueEx(hkTemp, REG_CLIENT_REALM_PARM, 0, NULL, (LPBYTE) realm, &dwSize);
898 if(rv != ERROR_SUCCESS) {/* what the ..? */
899 DebugEvent("Can't look up Realm rv [%d] size [%d] gle [%d]",rv, dwSize, GetLastError());
903 DebugEvent("Found Realm [%s]", realm);
904 if (strcmp(realm, domain)) {
910 if (realm) free(realm);
913 * If no realm was found and the logon domain is not a valid
914 * realm name (aka LOCALHOST or domain short name, attempt
915 * to identify the full domain name or use the krb5 default
918 * Possible sources of domain or realm information:
920 * HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\History
921 * MachineDomain REG_SZ
923 * HKLM\SYSTEM\CurrentControlSet\Control\Lsa\CachedMachineNames
924 * NameUserPrincipal REG_SZ MACHINE$@DOMAIN
926 * HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Domains\<DOMAIN>
928 if ( !ISREMOTE(opt->flags)) {
929 opt->realm = KFW_get_default_realm();
930 } else if ( strchr(domain, '.') == NULL) {
931 opt->realm = FindFullDomainName(domain);
932 if (opt->realm == NULL)
933 opt->realm = KFW_get_default_realm();
937 /* Obtain the username mapping (if any) */
943 rv = RegQueryValueEx(hkUserMap, REG_CLIENT_USERNAME_PARM, 0, &dwType, NULL, &dwSize);
944 if((rv == ERROR_SUCCESS || rv == ERROR_MORE_DATA) && dwType == REG_SZ) {
945 CHAR * usermap = NULL;
947 /* dwSize still has the size of the required buffer in bytes. */
948 usermap = malloc(dwSize*2);
953 rv = RegQueryValueEx(hkUserMap, REG_CLIENT_USERNAME_PARM, 0, NULL, (LPBYTE) usermap, &dwSize);
954 if(rv != ERROR_SUCCESS) {/* what the ..? */
955 DebugEvent("Can't look up Username rv [%d] size [%d] gle [%d]", rv, dwSize, GetLastError());
959 DebugEvent("Found Username [%s]", usermap);
960 if (strcmp(usermap, username)) {
961 opt->username = usermap;
966 if (usermap) free(usermap);
970 /* Determine if the username@realm is the LSA Kerberos principal (if any) */
971 if (!opt->username && !opt->realm && bKerberos) {
972 opt->flags |= LOGON_FLAG_LSA;
976 if(hkNp) RegCloseKey(hkNp);
977 if(hkDom) RegCloseKey(hkDom);
978 if(hkDoms) RegCloseKey(hkDoms);
979 if(hkUserMap) RegCloseKey(hkUserMap);
980 if(hkParm) RegCloseKey(hkParm);
983 #undef LOOKUPKEYCHAIN
987 /* Try to find out which cell the given path is in. We must retain
988 the contents of *cell in case of failure. *cell is assumed to be
989 at least cellLen chars */
990 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
991 struct ViceIoctl blob;
992 char tcell[MAX_PATH];
996 blob.out_size = MAX_PATH;
999 code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
1002 strncpy(cell, tcell, cellLen);
1003 cell[cellLen - 1] = '\0';
1011 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
1013 CPINFO CodePageInfo;
1015 GetCPInfo(CP_ACP, &CodePageInfo);
1017 if (CodePageInfo.MaxCharSize > 1)
1018 // Only supporting non-Unicode strings
1021 if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
1023 // Looks like unicode, better translate it
1024 // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
1025 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
1026 lpszOutputString, nOutStringLen-1, NULL, NULL);
1027 lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
1031 lpszOutputString[0] = '\0';
1033 } // UnicodeStringToANSI
1036 ObtainTokens( PLUID lpLogonId,
1037 LogonOptions_t *pOpt,
1046 CtxtHandle LogonContext;
1049 LogonSSP(lpLogonId, &LogonContext);
1050 ImpersonateSecurityContext(&LogonContext);
1052 if ( KFW_is_available() ) {
1053 char * principal, *p;
1056 SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
1058 if (ISLSA(pOpt->flags)) {
1059 KFW_import_windows_lsa();
1062 StringCchLength(pOpt->realm ? pOpt->realm : realm, MAX_DOMAIN_LENGTH, &tlen);
1064 StringCchLength(uname, MAX_USERNAME_LENGTH, &tlen);
1067 /* tlen is now the length of uname in characters */
1068 principal = (char *)malloc(len * sizeof(char));
1070 StringCchCopy(principal, len, uname);
1071 p = principal + tlen;
1073 StringCchCopy(p, len - tlen -1, pOpt->realm ? pOpt->realm : realm);
1074 code = KFW_AFS_get_cred(principal, cell, password, 0, NULL, preason);
1075 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
1076 principal, pOpt->smbName, cell, code);
1078 if (code == 0 && pOpt->theseCells) {
1079 p = pOpt->theseCells;
1081 if ( cm_stricmp_utf8(p, cell) ) {
1082 SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
1083 code2 = KFW_AFS_get_cred(principal, p, password, 0, NULL, preason);
1084 SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL);
1085 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
1086 principal, pOpt->smbName, p, code2);
1094 SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL);
1097 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
1098 uname, "", cell, password, NULL, 0, &pw_exp, 0,
1100 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2 Code[%x] uname[%s] smbname=[%s] Cell[%s] PwExp=[%d] Reason=[%s]",
1101 code, uname, pOpt->smbName, cell, pw_exp, *preason ? *preason : "");
1104 RevertSecurityContext(&LogonContext);
1105 DeleteSecurityContext(&LogonContext);
1113 LPCWSTR lpAuthentInfoType,
1114 LPVOID lpAuthentInfo,
1115 LPCWSTR lpPreviousAuthentInfoType,
1116 LPVOID lpPreviousAuthentInfo,
1117 LPWSTR lpStationName,
1118 LPVOID StationHandle,
1119 LPWSTR *lpLogonScript)
1121 char uname[MAX_USERNAME_LENGTH]="";
1122 char password[MAX_PASSWORD_LENGTH]="";
1123 char logonDomain[MAX_DOMAIN_LENGTH]="";
1124 char cell[256]="<non-integrated logon>";
1125 char homePath[MAX_PATH]="";
1126 char szLogonId[128] = "";
1128 MSV1_0_INTERACTIVE_LOGON *IL;
1135 BOOLEAN interactive;
1136 BOOLEAN domainKerberos = FALSE;
1138 DWORD LSPtype, LSPsize;
1141 HWND hwndOwner = (HWND)StationHandle;
1143 BOOLEAN afsWillAutoStart;
1145 BOOLEAN lowercased_name = TRUE;
1147 LogonOptions_t opt; /* domain specific logon options */
1151 /* Are we interactive? */
1152 interactive = (wcsicmp(lpStationName, L"WinSta0") == 0);
1154 #ifdef DISABLE_NON_INTERACTIVE
1155 /* Do not do anything if the logon session is not interactive. */
1160 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1161 0, KEY_QUERY_VALUE, &NPKey);
1162 LSPsize=sizeof(TraceOption);
1163 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
1164 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
1166 RegCloseKey (NPKey);
1168 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PROVIDER_SUBKEY,
1169 0, KEY_QUERY_VALUE, &NPKey);
1170 LSPsize=sizeof(Debug);
1171 RegQueryValueEx(NPKey, REG_CLIENT_DEBUG_PARM, NULL,
1172 &LSPtype, (LPBYTE)&Debug, &LSPsize);
1174 RegCloseKey (NPKey);
1176 DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart);
1178 /* Make sure the AFS Libraries are initialized */
1181 /* Initialize Logon Script to none */
1182 *lpLogonScript=NULL;
1184 /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for
1187 domainKerberos = !wcsicmp(lpAuthentInfoType,L"Kerberos:Interactive");
1189 if ( wcsicmp(lpAuthentInfoType,L"MSV1_0:Interactive") &&
1192 DebugEvent("Unsupported Authentication Info Type: %S",
1197 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
1199 /* Convert from Unicode to ANSI */
1201 if (!UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH) ||
1202 !UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH) ||
1203 !UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH))
1207 * The AD logon domain can be provided in the IL->LogonDomainName field
1208 * or as part of the IL->UserName field or both. If the IL->UserName
1209 * field contains a domain:
1210 * a) if there is no IL->LogonDomainName, use it as the domain
1211 * b) strip it from the username as we may combined the name with
1212 * another realm based upon our configuration
1214 ctemp = strchr(uname, '@');
1216 DebugEvent("Username contains a realm: %s", uname);
1219 StringCchCopy(logonDomain, MAX_DOMAIN_LENGTH, ctemp);
1225 GetDomainLogonOptions( lpLogonId, domainKerberos, uname, logonDomain, &opt);
1227 retryInterval = opt.retryInterval;
1228 sleepInterval = opt.sleepInterval;
1229 *lpLogonScript = opt.logonScript;
1231 if (retryInterval < sleepInterval)
1232 sleepInterval = retryInterval;
1234 DebugEvent("Got logon script: [%S]", opt.logonScript);
1236 afsWillAutoStart = AFSWillAutoStart();
1238 DebugEvent("LogonOption[%x], Service AutoStart[%d]",
1239 opt.LogonOption,afsWillAutoStart);
1241 /* Check for zero length password if integrated logon*/
1242 if ( ISLOGONINTEGRATED(opt.LogonOption) ) {
1243 if ( password[0] == 0 ) {
1244 DebugEvent0("Password is the empty string");
1246 reason = "zero length password is illegal";
1250 /* Get cell name if doing integrated logon.
1251 We might overwrite this if we are logging into an AD realm and we find out that
1252 the user's home dir is in some other cell. */
1253 DebugEvent0("About to call cm_GetRootCellName()");
1254 code = cm_GetRootCellName(cell);
1256 DebugEvent0("Unable to obtain Root Cell");
1258 reason = "unknown cell";
1260 DebugEvent("Default cell is %s", cell);
1264 /* We get the user's home directory path, if applicable, though we can't lookup the
1265 cell right away because the client service may not have started yet. This call
1266 also sets the AD_REALM flag in opt.flags if applicable. */
1267 if (ISREMOTE(opt.flags)) {
1268 DebugEvent0("Is Remote");
1269 GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
1273 AFSCreatePAG(lpLogonId);
1275 if (afsWillAutoStart) {
1277 * If the service is configured for auto start but hasn't started yet,
1280 if (!(IsServiceRunning() || IsServiceStartPending()))
1283 /* loop until AFS is started or fails. */
1284 while ( IsServiceStartPending() ) {
1288 while (IsServiceRunning() && code != KTC_NOCM && code != KTC_NOCMRPC && code != KTC_NOCELL) {
1289 DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
1290 opt.LogonOption,afsWillAutoStart);
1292 if (ISADREALM(opt.flags)) {
1293 code = GetFileCellName(homePath,cell,256);
1295 DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
1298 * Don't bail out if GetFileCellName failed.
1299 * The home dir may not be in AFS after all.
1304 /* if Integrated Logon */
1305 if (ISLOGONINTEGRATED(opt.LogonOption))
1307 code = ObtainTokens( lpLogonId, &opt, opt.username ? opt.username : uname,
1308 opt.realm ? opt.realm : logonDomain, cell, password, &reason);
1309 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name && !opt.username) {
1310 for ( ctemp = uname; *ctemp ; ctemp++) {
1311 *ctemp = tolower(*ctemp);
1313 lowercased_name = TRUE;
1317 /* is service started yet?*/
1319 /* If we've failed because the client isn't running yet and the
1320 * client is set to autostart (and therefore it makes sense for
1321 * us to wait for it to start) then sleep a while and try again.
1322 * If the error was something else, then give up. */
1323 if (code != KTC_NOCM && code != KTC_NOCMRPC)
1327 /*JUST check to see if its running*/
1328 if (IsServiceRunning())
1330 if (!IsServiceStartPending()) {
1332 reason = "AFS Service start failed";
1337 /* If the retry interval has expired and we still aren't
1338 * logged in, then just give up if we are not in interactive
1339 * mode or the failSilently flag is set, otherwise let the
1340 * user know we failed and give them a chance to try again. */
1341 if (retryInterval <= 0) {
1342 reason = "AFS not running";
1343 if (!interactive || opt.failSilently)
1345 flag = MessageBox(hwndOwner,
1346 "AFS is still starting. Retry?",
1348 MB_ICONQUESTION | MB_RETRYCANCEL);
1349 if (flag == IDCANCEL)
1352 /* Wait just a little while and try again */
1353 retryInterval = opt.retryInterval;
1357 Sleep(sleepInterval * 1000);
1358 retryInterval -= sleepInterval;
1360 DebugEvent0("while loop exited");
1363 /* remove any kerberos 5 tickets currently held by the SYSTEM account
1367 if (ISLOGONINTEGRATED(opt.LogonOption) && KFW_is_available()) {
1368 CtxtHandle LogonContext;
1370 LogonSSP(lpLogonId, &LogonContext);
1371 ImpersonateSecurityContext(&LogonContext);
1374 sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
1375 DebugEvent("copying cache for %s %s", uname, szLogonId);
1376 KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
1378 DebugEvent("Destroying tickets for %s", uname);
1379 KFW_AFS_destroy_tickets_for_principal(uname);
1381 RevertSecurityContext(&LogonContext);
1382 DeleteSecurityContext(&LogonContext);
1390 DebugEvent("Integrated login failed: %s", reason);
1392 StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
1394 if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
1395 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK|MB_ICONWARNING|MB_SYSTEMMODAL);
1397 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
1399 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
1401 DeregisterEventSource(h);
1403 code = MapAuthError(code);
1406 if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
1409 LocalFree(*lpLogonScript);
1410 *lpLogonScript = NULL;
1411 if (!afsWillAutoStart) // its not running, so if not autostart or integrated logon then just skip
1416 if (opt.theseCells) free(opt.theseCells);
1417 if (opt.smbName) free(opt.smbName);
1418 if (opt.realm) free(opt.realm);
1420 SecureZeroMemory(password, sizeof(password));
1422 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
1426 DWORD APIENTRY NPPasswordChangeNotify(
1427 LPCWSTR lpAuthentInfoType,
1428 LPVOID lpAuthentInfo,
1429 LPCWSTR lpPreviousAuthentInfoType,
1430 LPVOID lpPreviousAuthentInfo,
1431 LPWSTR lpStationName,
1432 LPVOID StationHandle,
1435 BOOLEAN interactive;
1437 /* Are we interactive? */
1438 interactive = (wcsicmp(lpStationName, L"WinSta0") == 0);
1440 /* Do not do anything if the logon session is not interactive. */
1444 /* Make sure the AFS Libraries are initialized */
1447 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
1451 #include <userenv.h>
1453 #include <afs/vice.h>
1454 #include <afs/fs_utils.h>
1456 BOOL IsPathInAfs(const CHAR *strPath)
1459 struct ViceIoctl blob;
1463 blob.out_size = 2048;
1466 code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
1473 typedef struct _WLX_NOTIFICATION_INFO {
1478 PWSTR WindowStation;
1481 PFNMSGECALLBACK pStatusCallback;
1482 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
1485 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
1487 DWORD LSPtype, LSPsize;
1490 /* Make sure the AFS Libraries are initialized */
1493 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1494 0, KEY_QUERY_VALUE, &NPKey);
1495 LSPsize=sizeof(TraceOption);
1496 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
1497 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
1499 RegCloseKey (NPKey);
1501 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PROVIDER_SUBKEY,
1502 0, KEY_QUERY_VALUE, &NPKey);
1503 LSPsize=sizeof(Debug);
1504 RegQueryValueEx(NPKey, REG_CLIENT_DEBUG_PARM, NULL,
1505 &LSPtype, (LPBYTE)&Debug, &LSPsize);
1507 RegCloseKey (NPKey);
1508 DebugEvent0("AFS_Startup_Event");
1511 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
1514 TCHAR profileDir[1024] = TEXT("");
1516 PTOKEN_USER tokenUser = NULL;
1518 DWORD LSPtype, LSPsize;
1520 DWORD LogoffPreserveTokens = 0;
1523 /* Make sure the AFS Libraries are initialized */
1526 DebugEvent0("AFS_Logoff_Event - Start");
1528 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1529 0, KEY_QUERY_VALUE, &NPKey);
1530 LSPsize=sizeof(LogoffPreserveTokens);
1531 RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
1532 &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
1533 RegCloseKey (NPKey);
1535 if (!LogoffPreserveTokens) {
1536 memset(&opt, 0, sizeof(LogonOptions_t));
1538 if (pInfo->UserName && pInfo->Domain) {
1539 char username[MAX_USERNAME_LENGTH] = "";
1540 char domain[MAX_DOMAIN_LENGTH] = "";
1543 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1544 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, (int)szlen,
1545 username, sizeof(username), NULL, NULL);
1547 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1548 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, (int)szlen,
1549 domain, sizeof(domain), NULL, NULL);
1551 GetDomainLogonOptions(NULL, FALSE, username, domain, &opt);
1554 if (ISREMOTE(opt.flags)) {
1555 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1557 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1558 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1560 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1562 DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1567 /* We can't use pInfo->Domain for the domain since in the cross realm case
1568 * this is source domain and not the destination domain.
1570 if (tokenUser && QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1571 WCHAR Domain[64]=L"";
1572 GetLocalShortDomain(Domain, sizeof(Domain));
1573 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1574 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1575 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1579 if (strlen(profileDir)) {
1580 DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1581 if (!IsPathInAfs(profileDir)) {
1582 if (code = ktc_ForgetAllTokens())
1583 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1585 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1587 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1590 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1594 LocalFree(tokenUser);
1596 DebugEvent0("AFS_Logoff_Event - Local Logon");
1597 if (code = ktc_ForgetAllTokens())
1598 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1600 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1603 DebugEvent0("AFS_Logoff_Event - Preserving Tokens");
1606 DebugEvent0("AFS_Logoff_Event - End");
1609 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1611 TCHAR profileDir[1024] = TEXT("");
1613 PTOKEN_USER tokenUser = NULL;
1615 WCHAR szUserW[128] = L"";
1616 char szUserA[128] = "";
1617 char szClient[MAX_PATH];
1618 char szPath[MAX_PATH] = "";
1624 /* Make sure the AFS Libraries are initialized */
1627 DebugEvent0("AFS_Logon_Event - Start");
1629 DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1631 memset(&opt, 0, sizeof(LogonOptions_t));
1633 if (pInfo->UserName && pInfo->Domain) {
1634 char username[MAX_USERNAME_LENGTH] = "";
1635 char domain[MAX_DOMAIN_LENGTH] = "";
1638 DebugEvent0("AFS_Logon_Event - pInfo UserName and Domain");
1640 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1641 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, (int)szlen,
1642 username, sizeof(username), NULL, NULL);
1644 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1645 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, (int)szlen,
1646 domain, sizeof(domain), NULL, NULL);
1648 DebugEvent0("AFS_Logon_Event - Calling GetDomainLogonOptions");
1649 GetDomainLogonOptions(NULL, FALSE, username, domain, &opt);
1651 if (!pInfo->UserName)
1652 DebugEvent0("AFS_Logon_Event - No pInfo->UserName");
1654 DebugEvent0("AFS_Logon_Event - No pInfo->Domain");
1657 DebugEvent("AFS_Logon_Event - opt.LogonOption = %lX opt.flags = %lX",
1658 opt.LogonOption, opt.flags);
1660 if (!ISLOGONINTEGRATED(opt.LogonOption) || !ISREMOTE(opt.flags)) {
1661 DebugEvent0("AFS_Logon_Event - Logon is not integrated or not remote");
1662 goto done_logon_event;
1665 DebugEvent0("AFS_Logon_Event - Calling GetTokenInformation");
1667 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1669 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1670 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1672 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1674 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1679 /* We can't use pInfo->Domain for the domain since in the cross realm case
1680 * this is source domain and not the destination domain.
1682 if (tokenUser && QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1683 WCHAR Domain[64]=L"";
1684 GetLocalShortDomain(Domain, sizeof(Domain));
1685 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1686 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1687 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1691 if (strlen(profileDir)) {
1692 DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1694 DebugEvent0("AFS_Logon_Event - Unable to load profile");
1698 dwSize = sizeof(szUserA);
1699 if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1700 StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1701 WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1706 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1707 StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1709 DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1711 memset (&nr, 0x00, sizeof(NETRESOURCE));
1712 nr.dwType=RESOURCETYPE_DISK;
1714 nr.lpRemoteName=szPath;
1715 res = WNetAddConnection2(&nr,NULL,szUserA,0);
1717 DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1718 szPath, szUserA,res);
1720 DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1722 DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1725 LocalFree(tokenUser);
1727 DebugEvent0("AFS_Logon_Event - End");
1731 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1733 NTSTATUS Status = 0;
1734 TOKEN_STATISTICS Stats;
1740 *ppSessionData = NULL;
1742 Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1746 Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1747 if ( FAILED(Status) || !ppSessionData )
1753 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1756 WCHAR szUserW[128] = L"";
1757 char szUserA[128] = "";
1758 char szPath[MAX_PATH] = "";
1759 char szLogonId[128] = "";
1761 char filename[MAX_PATH] = "";
1762 char newfilename[MAX_PATH] = "";
1763 char commandline[MAX_PATH+256] = "";
1764 STARTUPINFO startupinfo;
1765 PROCESS_INFORMATION procinfo;
1766 HANDLE hf = INVALID_HANDLE_VALUE;
1768 LUID LogonId = {0, 0};
1769 PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1771 HKEY hKey1 = NULL, hKey2 = NULL;
1773 /* Make sure the KFW Libraries are initialized */
1776 DebugEvent0("KFW_Logon_Event - Start");
1778 GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1780 if ( pLogonSessionData ) {
1781 LogonId = pLogonSessionData->LogonId;
1782 DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1784 sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1785 LsaFreeReturnBuffer( pLogonSessionData );
1787 DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1791 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1792 if ( count > sizeof(filename) || count == 0 ) {
1793 GetWindowsDirectory(filename, sizeof(filename));
1796 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1797 if ( count > sizeof(filename) || count == 0 ) {
1798 GetWindowsDirectory(filename, sizeof(filename));
1801 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) {
1802 DebugEvent0("KFW_Logon_Event - filename too long");
1806 strcat(filename, "\\");
1807 strcat(filename, szLogonId);
1809 hf = CreateFile(filename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING,
1810 FILE_ATTRIBUTE_NORMAL, NULL);
1811 if (hf == INVALID_HANDLE_VALUE) {
1812 DebugEvent0("KFW_Logon_Event - file cannot be opened");
1817 if (KFW_AFS_set_file_cache_dacl(filename, pInfo->hToken)) {
1818 DebugEvent0("KFW_Logon_Event - unable to set dacl");
1819 DeleteFile(filename);
1823 if (KFW_AFS_obtain_user_temp_directory(pInfo->hToken, newfilename, sizeof(newfilename))) {
1824 DebugEvent0("KFW_Logon_Event - unable to obtain temp directory");
1828 if ( strlen(newfilename) + strlen(szLogonId) + 2 > sizeof(newfilename) ) {
1829 DebugEvent0("KFW_Logon_Event - new filename too long");
1833 strcat(newfilename, "\\");
1834 strcat(newfilename, szLogonId);
1836 if (!MoveFileEx(filename, newfilename,
1837 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
1838 DebugEvent("KFW_Logon_Event - MoveFileEx failed GLE = 0x%x", GetLastError());
1842 sprintf(commandline, "afscpcc.exe \"%s\"", newfilename);
1844 GetStartupInfo(&startupinfo);
1845 if (CreateProcessAsUser( pInfo->hToken,
1851 CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1857 DebugEvent("KFW_Logon_Event - CommandLine %s", commandline);
1859 WaitForSingleObject(procinfo.hProcess, 30000);
1861 CloseHandle(procinfo.hThread);
1862 CloseHandle(procinfo.hProcess);
1864 DebugEvent0("KFW_Logon_Event - CreateProcessFailed");
1867 DeleteFile(filename);
1869 DebugEvent0("KFW_Logon_Event - End");