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
14 #include <sys/types.h>
20 #include <afs/param.h>
22 #include <afs/pioctl_nt.h>
23 #include <afs/kautils.h>
26 #include "cm_config.h"
30 DWORD TraceOption = 0;
35 #define AFS_LOGON_EVENT_NAME TEXT("AFS Logon")
37 void DebugEvent0(char *a)
39 HANDLE h; char *ptbuf[1];
40 if (!ISLOGONTRACE(TraceOption))
42 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
44 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
45 DeregisterEventSource(h);
49 void DebugEvent(char *b,...)
51 HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
54 if (!ISLOGONTRACE(TraceOption))
57 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
59 StringCbVPrintf(buf, MAXBUF_+1,b,marker);
62 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
63 DeregisterEventSource(h);
67 static HANDLE hInitMutex = NULL;
68 static BOOL bInit = FALSE;
70 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
74 case DLL_PROCESS_ATTACH:
75 /* Initialization Mutex */
76 hInitMutex = CreateMutex(NULL, FALSE, NULL);
79 case DLL_PROCESS_DETACH:
80 CloseHandle(hInitMutex);
83 case DLL_THREAD_ATTACH:
84 case DLL_THREAD_DETACH:
86 /* Everything else succeeds but does nothing. */
93 void AfsLogonInit(void)
95 if ( bInit == FALSE ) {
96 if ( WaitForSingleObject( hInitMutex, INFINITE ) == WAIT_OBJECT_0 ) {
97 if ( bInit == FALSE ) {
103 ReleaseMutex(hInitMutex);
108 CHAR *GenRandomName(CHAR *pbuf)
111 srand( (unsigned)time( NULL ) );
112 for (i=0;i<MAXRANDOMNAMELEN-1;i++)
113 pbuf[i]='a'+(rand() % 26);
114 pbuf[MAXRANDOMNAMELEN-1]=0;
118 BOOLEAN AFSWillAutoStart(void)
123 BOOLEAN result = FALSE;
124 LPQUERY_SERVICE_CONFIG pConfig = NULL;
128 /* Open services manager */
129 scm = OpenSCManager(NULL, NULL, GENERIC_READ);
130 if (!scm) return FALSE;
132 /* Open AFSD service */
133 svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
137 /* Query AFSD service config, first just to get buffer size */
138 /* Expected to fail, so don't test return value */
139 (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
140 status = GetLastError();
141 if (status != ERROR_INSUFFICIENT_BUFFER)
144 /* Allocate buffer */
145 pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
149 /* Query AFSD service config, this time for real */
150 flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
154 /* Is it autostart? */
155 if (pConfig->dwStartType < SERVICE_DEMAND_START)
161 CloseServiceHandle(svc);
163 CloseServiceHandle(scm);
168 DWORD MapAuthError(DWORD code)
171 /* Unfortunately, returning WN_NO_NETWORK results in the MPR abandoning
172 * logon scripts for all credential managers, although they will still
173 * receive logon notifications. Since we don't want this, we return
174 * WN_SUCCESS. This is highly undesirable, but we also don't want to
175 * break other network providers.
179 return WN_NO_NETWORK; */
180 default: return WN_SUCCESS;
184 DWORD APIENTRY NPGetCaps(DWORD index)
188 /* Don't have our own type; use somebody else's. */
189 return WNNC_NET_SUN_PC_NFS;
192 /* Say we are already started, even though we might wait after we receive NPLogonNotify */
201 NetUserGetProfilePath( LPCWSTR Domain, LPCWSTR UserName, char * profilePath,
202 DWORD profilePathLen )
205 LPWSTR ServerName = NULL;
206 LPUSER_INFO_3 p3 = NULL;
208 NetGetAnyDCName(NULL, Domain, (LPBYTE *)&ServerName);
209 /* if NetGetAnyDCName fails, ServerName == NULL
210 * NetUserGetInfo will obtain local user information
212 code = NetUserGetInfo(ServerName, UserName, 3, (LPBYTE *)&p3);
213 if (code == NERR_Success)
215 code = NERR_UserNotFound;
217 if (p3->usri3_profile) {
218 DWORD len = lstrlenW(p3->usri3_profile);
220 /* Convert From Unicode to ANSI (UTF-8 for future) */
221 len = len < profilePathLen ? len : profilePathLen - 1;
222 WideCharToMultiByte(CP_UTF8, 0, p3->usri3_profile, len, profilePath, len, NULL, NULL);
223 profilePath[len] = '\0';
227 NetApiBufferFree(p3);
231 NetApiBufferFree(ServerName);
235 BOOL IsServiceRunning (void)
237 SERVICE_STATUS Status;
239 memset (&Status, 0x00, sizeof(Status));
240 Status.dwCurrentState = SERVICE_STOPPED;
242 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
245 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
247 QueryServiceStatus (hService, &Status);
248 CloseServiceHandle (hService);
251 CloseServiceHandle (hManager);
253 DebugEvent("AFS AfsLogon - Test Service Running","Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
254 return (Status.dwCurrentState == SERVICE_RUNNING);
257 /* LOOKUPKEYCHAIN: macro to look up the value in the list of keys in order until it's found
258 v:variable to receive value (reference type)
260 d:default, in case the value isn't on any of the keys
262 #define LOOKUPKEYCHAIN(v,t,d,n) \
264 rv = ~ERROR_SUCCESS; \
267 dwSize = sizeof(v); \
268 rv = RegQueryValueEx(hkDom, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
269 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDom with type [%d]", dwType); \
271 if(hkDoms && (rv != ERROR_SUCCESS || dwType != t)) { \
272 dwSize = sizeof(v); \
273 rv = RegQueryValueEx(hkDoms, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
274 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDoms with type [%d]", dwType); \
276 if(hkNp && (rv != ERROR_SUCCESS || dwType != t)) { \
277 dwSize = sizeof(v); \
278 rv = RegQueryValueEx(hkNp, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
279 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkNp with type [%d]", dwType); \
281 if(rv != ERROR_SUCCESS || dwType != t) { \
283 DebugEvent(#v " being set to default"); \
287 /* Get domain specific configuration info. We are returning void because if anything goes wrong
288 we just return defaults.
291 GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
292 HKEY hkParm = NULL; /* Service parameter */
293 HKEY hkNp = NULL; /* network provider key */
294 HKEY hkDoms = NULL; /* domains key */
295 HKEY hkDom = NULL; /* DOMAINS/domain key */
301 char computerName[MAX_COMPUTERNAME_LENGTH + 1];
304 DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
305 /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
306 opt->flags = LOGON_FLAG_REMOTE;
308 dwSize = MAX_COMPUTERNAME_LENGTH;
309 if(GetComputerName(computerName, &dwSize)) {
310 if(!stricmp(computerName, domain)) {
311 effDomain = "LOCALHOST";
312 opt->flags = LOGON_FLAG_LOCAL;
320 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY, 0, KEY_READ, &hkParm );
321 if(rv != ERROR_SUCCESS) {
323 DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
326 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CLIENT_PROVIDER_KEY, 0, KEY_READ, &hkNp );
327 if(rv != ERROR_SUCCESS) {
329 DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
333 rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
334 if( rv != ERROR_SUCCESS ) {
336 DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
340 if(hkDoms && effDomain) {
341 rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
342 if( rv != ERROR_SUCCESS ) {
344 DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
345 /* If none of the domains match, we shouldn't use the domain key either */
350 DebugEvent("Not opening domain key for [%s]", effDomain);
352 /* Each individual can either be specified on the domain key, the domains key or in the
353 net provider key. They fail over in that order. If none is found, we just use the
357 LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
359 /* FailLoginsSilently */
360 dwSize = sizeof(dwDummy);
361 rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
362 if (rv != ERROR_SUCCESS)
363 LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
364 opt->failSilently = !!dwDummy;
367 LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
370 LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
372 opt->logonScript = NULL;
375 if(!ISLOGONINTEGRATED(opt->LogonOption)) {
376 goto cleanup; /* no need to lookup the logon script */
379 /* come up with SMB username */
380 if(ISHIGHSECURITY(opt->LogonOption)) {
381 opt->smbName = malloc( MAXRANDOMNAMELEN );
382 GenRandomName(opt->smbName);
384 /* username and domain for logon session is not necessarily the same as
385 username and domain passed into network provider. */
386 PSECURITY_LOGON_SESSION_DATA plsd;
387 char lsaUsername[MAX_USERNAME_LENGTH];
388 char lsaDomain[MAX_DOMAIN_LENGTH];
391 LsaGetLogonSessionData(lpLogonId, &plsd);
393 UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
394 UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
396 DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
398 if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
403 if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
410 opt->smbName = malloc(len);
412 StringCbCopy(opt->smbName, len, lsaDomain);
413 StringCbCat(opt->smbName, len, "\\");
414 StringCbCat(opt->smbName, len, lsaUsername);
416 strlwr(opt->smbName);
419 LsaFreeReturnBuffer(plsd);
422 DebugEvent("Looking up logon script");
424 /* First find out where the key is */
429 rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
430 if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
432 DebugEvent("Located logon script in hkDom");
435 rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
436 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
438 DebugEvent("Located logon script in hkDoms");
440 /* Note that the LogonScript in the NP key is only used if we are doing high security. */
441 else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
442 rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
443 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
445 DebugEvent("Located logon script in hkNp");
449 WCHAR *regscript = NULL;
450 WCHAR *regexscript = NULL;
451 WCHAR *regexuscript = NULL;
452 WCHAR *wuname = NULL;
457 StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
460 wuname = malloc(len * sizeof(WCHAR));
461 MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,len*sizeof(WCHAR));
463 DebugEvent("Username is set for [%S]", wuname);
465 /* dwSize still has the size of the required buffer in bytes. */
466 regscript = malloc(dwSize);
467 rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
468 if(rv != ERROR_SUCCESS) {/* what the ..? */
469 DebugEvent("Can't look up logon script [%d]",rv);
470 goto doneLogonScript;
473 DebugEvent("Found logon script [%S]", regscript);
475 if(dwType == REG_EXPAND_SZ) {
478 dwSize += MAX_PATH * sizeof(WCHAR); /* make room for environment expansion. */
479 regexscript = malloc(dwSize);
480 dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
482 regscript = regexscript;
484 if(dwReq > (dwSize / sizeof(WCHAR))) {
485 DebugEvent("Overflow while expanding environment strings.");
486 goto doneLogonScript;
490 DebugEvent("After expanding env strings [%S]", regscript);
492 if(wcsstr(regscript, L"%s")) {
493 dwSize += len * sizeof(WCHAR); /* make room for username expansion */
494 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
495 hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
497 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
498 hr = StringCbCopyW(regexuscript, dwSize, regscript);
501 DebugEvent("After expanding username [%S]", regexuscript);
504 opt->logonScript = regexuscript;
506 LocalFree(regexuscript);
509 if(wuname) free(wuname);
510 if(regscript) free(regscript);
511 if(regexscript) free(regexscript);
515 if(hkNp) RegCloseKey(hkNp);
516 if(hkDom) RegCloseKey(hkDom);
517 if(hkDoms) RegCloseKey(hkDoms);
518 if(hkParm) RegCloseKey(hkParm);
521 #undef LOOKUPKEYCHAIN
523 /* Try to find out which cell the given path is in. We must retain
524 the contents of *cell in case of failure. *cell is assumed to be
525 at least cellLen chars */
526 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
527 struct ViceIoctl blob;
528 char tcell[MAX_PATH];
532 blob.out_size = MAX_PATH;
535 code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
538 strncpy(cell, tcell, cellLen);
539 cell[cellLen - 1] = '\0';
547 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
551 GetCPInfo(CP_ACP, &CodePageInfo);
553 if (CodePageInfo.MaxCharSize > 1)
554 // Only supporting non-Unicode strings
557 if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
559 // Looks like unicode, better translate it
560 // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
561 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
562 lpszOutputString, nOutStringLen-1, NULL, NULL);
563 lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
567 lpszOutputString[0] = '\0';
569 } // UnicodeStringToANSI
571 DWORD APIENTRY NPLogonNotify(
573 LPCWSTR lpAuthentInfoType,
574 LPVOID lpAuthentInfo,
575 LPCWSTR lpPreviousAuthentInfoType,
576 LPVOID lpPreviousAuthentInfo,
577 LPWSTR lpStationName,
578 LPVOID StationHandle,
579 LPWSTR *lpLogonScript)
581 char uname[MAX_USERNAME_LENGTH]="";
582 char password[MAX_PASSWORD_LENGTH]="";
583 char logonDomain[MAX_DOMAIN_LENGTH]="";
584 char cell[256]="<non-integrated logon>";
585 char homePath[MAX_PATH]="";
587 MSV1_0_INTERACTIVE_LOGON *IL;
597 DWORD LSPtype, LSPsize;
600 HWND hwndOwner = (HWND)StationHandle;
602 BOOLEAN afsWillAutoStart;
604 BOOLEAN uppercased_name = TRUE;
606 LogonOptions_t opt; /* domain specific logon options */
610 /* Make sure the AFS Libraries are initialized */
613 /* Initialize Logon Script to none */
616 /* TODO: We should check the value of lpAuthentInfoType before assuming that it is
617 MSV1_0_INTERACTIVE_LOGON though for our purposes KERB_INTERACTIVE_LOGON is
618 co-incidentally equivalent. */
619 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
621 /* Are we interactive? */
622 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
624 /* Convert from Unicode to ANSI */
626 /*TODO: Use SecureZeroMemory to erase passwords */
627 UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
628 UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
629 UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
631 /* Make sure AD-DOMANS sent from login that is sent to us is striped */
632 ctemp = strchr(uname, '@');
633 if (ctemp) *ctemp = 0;
635 /* is the name all uppercase? */
636 for ( ctemp = uname; *ctemp ; ctemp++) {
637 if ( islower(*ctemp) ) {
638 uppercased_name = FALSE;
643 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
644 0, KEY_QUERY_VALUE, &NPKey);
645 LSPsize=sizeof(TraceOption);
646 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
647 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
655 GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
656 retryInterval = opt.retryInterval;
657 sleepInterval = opt.sleepInterval;
658 *lpLogonScript = opt.logonScript;
660 DebugEvent("Got logon script: %S",opt.logonScript);
662 afsWillAutoStart = AFSWillAutoStart();
664 DebugEvent("LogonOption[%x], Service AutoStart[%d]",
665 opt.LogonOption,afsWillAutoStart);
667 /* Check for zero length password if integrated logon*/
668 if ( ISLOGONINTEGRATED(opt.LogonOption) ) {
669 if ( password[0] == 0 ) {
670 DebugEvent("Password is the empty string");
672 reason = "zero length password is illegal";
676 /* Get cell name if doing integrated logon.
677 We might overwrite this if we are logging into an AD realm and we find out that
678 the user's home dir is in some other cell. */
679 DebugEvent("About to call cm_GetRootCellName(%s)",cell);
680 code = cm_GetRootCellName(cell);
682 DebugEvent("Unable to obtain Root Cell");
684 reason = "unknown cell";
687 DebugEvent("Cell is %s",cell);
690 /* We get the user's home directory path, if applicable, though we can't lookup the
691 cell right away because the client service may not have started yet. This call
692 also sets the AD_REALM flag in opt.flags if applicable. */
693 if(ISREMOTE(opt.flags)) {
694 DebugEvent("Is Remote");
695 GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
699 /* loop until AFS is started. */
701 DebugEvent("while(TRUE) LogonOption[%x], Service AutoStart[%d]",
702 opt.LogonOption,afsWillAutoStart);
704 if(ISADREALM(opt.flags)) {
705 code = GetFileCellName(homePath,cell,256);
707 DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
709 /* Don't bail out if GetFileCellName failed.
710 * The home dir may not be in AFS after all.
715 /* if Integrated Logon */
716 if (ISLOGONINTEGRATED(opt.LogonOption))
718 if ( KFW_is_available() ) {
719 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
720 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",uname,opt.smbName,cell,code);
723 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
724 uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
726 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2","Code[%x]",
729 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && uppercased_name ) {
730 for ( ctemp = uname; *ctemp ; ctemp++) {
731 *ctemp = tolower(*ctemp);
733 uppercased_name = FALSE;
738 /*JUST check to see if its running*/
739 if (IsServiceRunning())
742 if (!afsWillAutoStart)
746 /* is service started yet?*/
747 DebugEvent("AFS AfsLogon - ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s]",
750 /* If we've failed because the client isn't running yet and the
751 * client is set to autostart (and therefore it makes sense for
752 * us to wait for it to start) then sleep a while and try again.
753 * If the error was something else, then give up. */
754 if (code != KTC_NOCM && code != KTC_NOCMRPC || !afsWillAutoStart)
757 /* If the retry interval has expired and we still aren't
758 * logged in, then just give up if we are not in interactive
759 * mode or the failSilently flag is set, otherwise let the
760 * user know we failed and give them a chance to try again. */
761 if (retryInterval <= 0) {
762 reason = "AFS not running";
763 if (!interactive || opt.failSilently)
765 flag = MessageBox(hwndOwner,
766 "AFS is still starting. Retry?",
768 MB_ICONQUESTION | MB_RETRYCANCEL);
769 if (flag == IDCANCEL)
772 /* Wait just a little while and try again */
773 retryInterval = sleepInterval = DEFAULT_SLEEP_INTERVAL;
776 if (retryInterval < sleepInterval)
777 sleepInterval = retryInterval;
779 Sleep(sleepInterval * 1000);
781 retryInterval -= sleepInterval;
784 DebugEvent("while loop exited");
785 /* remove any kerberos 5 tickets currently held by the SYSTEM account */
786 if ( KFW_is_available() )
787 KFW_AFS_destroy_tickets_for_cell(cell);
794 StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
796 if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
797 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
799 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
801 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
803 DeregisterEventSource(h);
805 code = MapAuthError(code);
808 if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
811 LocalFree(*lpLogonScript);
812 *lpLogonScript = NULL;
813 if (!afsWillAutoStart) // its not running, so if not autostart or integrated logon then just skip
819 if(opt.smbName) free(opt.smbName);
821 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
825 DWORD APIENTRY NPPasswordChangeNotify(
826 LPCWSTR lpAuthentInfoType,
827 LPVOID lpAuthentInfo,
828 LPCWSTR lpPreviousAuthentInfoType,
829 LPVOID lpPreviousAuthentInfo,
830 LPWSTR lpStationName,
831 LPVOID StationHandle,
834 /* Make sure the AFS Libraries are initialized */
837 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
843 #include <afs/vice.h>
844 #include <afs/fs_utils.h>
846 BOOL IsPathInAfs(const CHAR *strPath)
849 struct ViceIoctl blob;
853 blob.out_size = 2048;
856 code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
863 typedef struct _WLX_NOTIFICATION_INFO {
871 PFNMSGECALLBACK pStatusCallback;
872 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
875 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
877 DWORD LSPtype, LSPsize;
880 /* Make sure the AFS Libraries are initialized */
883 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
884 0, KEY_QUERY_VALUE, &NPKey);
885 LSPsize=sizeof(TraceOption);
886 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
887 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
890 DebugEvent0("AFS_Startup_Event");
893 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
896 TCHAR profileDir[1024] = TEXT("");
898 PTOKEN_USER tokenUser = NULL;
902 /* Make sure the AFS Libraries are initialized */
905 DebugEvent0("AFS_Logoff_Event - Starting");
907 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
909 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
910 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
912 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
914 DebugEvent("GetTokenInformation failed: GLE = %lX", GetLastError());
919 /* We can't use pInfo->Domain for the domain since in the cross realm case
920 * this is source domain and not the destination domain.
922 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
923 WCHAR Domain[64]=L"";
924 GetLocalShortDomain(Domain, sizeof(Domain));
925 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
926 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
927 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
931 if (strlen(profileDir)) {
932 DebugEvent("Profile Directory: %s", profileDir);
933 if (!IsPathInAfs(profileDir)) {
934 if (code = ktc_ForgetAllTokens())
935 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
937 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
939 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
942 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
946 LocalFree(tokenUser);