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>
19 #include <afs/param.h>
21 #include <afs/pioctl_nt.h>
22 #include <afs/kautils.h>
25 #include "cm_config.h"
29 DWORD TraceOption = 0;
34 #define AFS_LOGON_EVENT_NAME TEXT("AFS Logon")
36 void DebugEvent0(char *a)
38 HANDLE h; char *ptbuf[1];
39 if (!ISLOGONTRACE(TraceOption))
41 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
43 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
44 DeregisterEventSource(h);
48 void DebugEvent(char *b,...)
50 HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
53 if (!ISLOGONTRACE(TraceOption))
56 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
58 StringCbVPrintf(buf, MAXBUF_+1,b,marker);
61 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);\
62 DeregisterEventSource(h);
66 CHAR *GenRandomName(CHAR *pbuf)
69 srand( (unsigned)time( NULL ) );
70 for (i=0;i<MAXRANDOMNAMELEN-1;i++)
71 pbuf[i]='a'+(rand() % 26);
72 pbuf[MAXRANDOMNAMELEN-1]=0;
76 BOOLEAN AFSWillAutoStart(void)
81 BOOLEAN result = FALSE;
82 LPQUERY_SERVICE_CONFIG pConfig = NULL;
86 /* Open services manager */
87 scm = OpenSCManager(NULL, NULL, GENERIC_READ);
88 if (!scm) return FALSE;
90 /* Open AFSD service */
91 svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
95 /* Query AFSD service config, first just to get buffer size */
96 /* Expected to fail, so don't test return value */
97 (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
98 status = GetLastError();
99 if (status != ERROR_INSUFFICIENT_BUFFER)
102 /* Allocate buffer */
103 pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
107 /* Query AFSD service config, this time for real */
108 flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
112 /* Is it autostart? */
113 if (pConfig->dwStartType < SERVICE_DEMAND_START)
119 CloseServiceHandle(svc);
121 CloseServiceHandle(scm);
126 DWORD MapAuthError(DWORD code)
129 /* Unfortunately, returning WN_NO_NETWORK results in the MPR abandoning
130 * logon scripts for all credential managers, although they will still
131 * receive logon notifications. Since we don't want this, we return
132 * WN_SUCCESS. This is highly undesirable, but we also don't want to
133 * break other network providers.
137 return WN_NO_NETWORK; */
138 default: return WN_SUCCESS;
142 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
146 case DLL_PROCESS_ATTACH:
147 /* Initialize AFS libraries */
153 /* Everything else succeeds but does nothing. */
154 case DLL_PROCESS_DETACH:
155 case DLL_THREAD_ATTACH:
156 case DLL_THREAD_DETACH:
164 DWORD APIENTRY NPGetCaps(DWORD index)
168 /* Don't have our own type; use somebody else's. */
169 return WNNC_NET_SUN_PC_NFS;
172 /* Say we are already started, even though we might wait after we receive NPLogonNotify */
180 BOOL IsServiceRunning (void)
182 SERVICE_STATUS Status;
184 memset (&Status, 0x00, sizeof(Status));
185 Status.dwCurrentState = SERVICE_STOPPED;
187 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
190 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
192 QueryServiceStatus (hService, &Status);
193 CloseServiceHandle (hService);
196 CloseServiceHandle (hManager);
198 DebugEvent("AFS AfsLogon - Test Service Running","Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
199 return (Status.dwCurrentState == SERVICE_RUNNING);
202 /* LOOKUPKEYCHAIN: macro to look up the value in the list of keys in order until it's found
203 v:variable to receive value (reference type)
205 d:default, in case the value isn't on any of the keys
207 #define LOOKUPKEYCHAIN(v,t,d,n) \
209 rv = ~ERROR_SUCCESS; \
212 dwSize = sizeof(v); \
213 rv = RegQueryValueEx(hkDom, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
214 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDom with type [%d]", dwType); \
216 if(hkDoms && (rv != ERROR_SUCCESS || dwType != t)) { \
217 dwSize = sizeof(v); \
218 rv = RegQueryValueEx(hkDoms, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
219 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDoms with type [%d]", dwType); \
221 if(hkNp && (rv != ERROR_SUCCESS || dwType != t)) { \
222 dwSize = sizeof(v); \
223 rv = RegQueryValueEx(hkNp, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
224 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkNp with type [%d]", dwType); \
226 if(rv != ERROR_SUCCESS || dwType != t) { \
228 DebugEvent(#v " being set to default"); \
232 /* Get domain specific configuration info. We are returning void because if anything goes wrong
233 we just return defaults.
235 void GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
236 HKEY hkParm = NULL; /* Service parameter */
237 HKEY hkNp = NULL; /* network provider key */
238 HKEY hkDoms = NULL; /* domains key */
239 HKEY hkDom = NULL; /* DOMAINS/domain key */
245 char computerName[MAX_COMPUTERNAME_LENGTH + 1];
248 DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
249 /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
250 opt->flags = LOGON_FLAG_REMOTE;
252 dwSize = MAX_COMPUTERNAME_LENGTH;
253 if(GetComputerName(computerName, &dwSize)) {
254 if(!stricmp(computerName, domain)) {
255 effDomain = "LOCALHOST";
256 opt->flags = LOGON_FLAG_LOCAL;
264 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY, 0, KEY_READ, &hkParm );
265 if(rv != ERROR_SUCCESS) {
267 DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
270 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CLIENT_PROVIDER_KEY, 0, KEY_READ, &hkNp );
271 if(rv != ERROR_SUCCESS) {
273 DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
277 rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
278 if( rv != ERROR_SUCCESS ) {
280 DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
284 if(hkDoms && effDomain) {
285 rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
286 if( rv != ERROR_SUCCESS ) {
288 DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
289 /* If none of the domains match, we shouldn't use the domain key either */
294 DebugEvent("Not opening domain key for [%s]", effDomain);
296 /* Each individual can either be specified on the domain key, the domains key or in the
297 net provider key. They fail over in that order. If none is found, we just use the
301 LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
303 /* FailLoginsSilently */
304 dwSize = sizeof(dwDummy);
305 rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
306 if(rv != ERROR_SUCCESS)
307 LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
308 opt->failSilently = !!dwDummy;
311 LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
314 LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
316 opt->logonScript = NULL;
319 if(!ISLOGONINTEGRATED(opt->LogonOption)) {
320 goto cleanup; /* no need to lookup the logon script */
323 /* come up with SMB username */
324 if(ISHIGHSECURITY(opt->LogonOption)) {
325 opt->smbName = malloc( MAXRANDOMNAMELEN );
326 GenRandomName(opt->smbName);
328 /* username and domain for logon session is not necessarily the same as
329 username and domain passed into network provider. */
330 PSECURITY_LOGON_SESSION_DATA plsd;
331 char lsaUsername[MAX_USERNAME_LENGTH];
332 char lsaDomain[MAX_DOMAIN_LENGTH];
335 LsaGetLogonSessionData(lpLogonId, &plsd);
337 UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
338 UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
340 DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
342 if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
347 if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
354 opt->smbName = malloc(len);
356 StringCbCopy(opt->smbName, len, lsaDomain);
357 StringCbCat(opt->smbName, len, "\\");
358 StringCbCat(opt->smbName, len, lsaUsername);
360 strlwr(opt->smbName);
363 LsaFreeReturnBuffer(plsd);
366 DebugEvent("Looking up logon script");
368 /* First find out where the key is */
373 rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
374 if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
376 DebugEvent("Located logon script in hkDom");
379 rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
380 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
382 DebugEvent("Located logon script in hkDoms");
384 /* Note that the LogonScript in the NP key is only used if we are doing high security. */
385 else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
386 rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
387 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
389 DebugEvent("Located logon script in hkNp");
393 WCHAR *regscript = NULL;
394 WCHAR *regexscript = NULL;
395 WCHAR *regexuscript = NULL;
396 WCHAR *wuname = NULL;
401 StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
404 wuname = malloc(len * sizeof(WCHAR));
405 MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,len*sizeof(WCHAR));
407 DebugEvent("Username is set for [%S]", wuname);
409 /* dwSize still has the size of the required buffer in bytes. */
410 regscript = malloc(dwSize);
411 rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
412 if(rv != ERROR_SUCCESS) {/* what the ..? */
413 DebugEvent("Can't look up logon script [%d]",rv);
414 goto doneLogonScript;
417 DebugEvent("Found logon script [%S]", regscript);
419 if(dwType == REG_EXPAND_SZ) {
422 dwSize += MAX_PATH * sizeof(WCHAR); /* make room for environment expansion. */
423 regexscript = malloc(dwSize);
424 dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
426 regscript = regexscript;
428 if(dwReq > (dwSize / sizeof(WCHAR))) {
429 DebugEvent("Overflow while expanding environment strings.");
430 goto doneLogonScript;
434 DebugEvent("After expanding env strings [%S]", regscript);
436 if(wcsstr(regscript, L"%s")) {
437 dwSize += len * sizeof(WCHAR); /* make room for username expansion */
438 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
439 hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
441 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
442 hr = StringCbCopyW(regexuscript, dwSize, regscript);
445 DebugEvent("After expanding username [%S]", regexuscript);
448 opt->logonScript = regexuscript;
450 LocalFree(regexuscript);
453 if(wuname) free(wuname);
454 if(regscript) free(regscript);
455 if(regexscript) free(regexscript);
459 if(hkNp) RegCloseKey(hkNp);
460 if(hkDom) RegCloseKey(hkDom);
461 if(hkDoms) RegCloseKey(hkDoms);
462 if(hkParm) RegCloseKey(hkParm);
465 #undef LOOKUPKEYCHAIN
467 /* Try to find out which cell the given path is in. We must retain
468 the contents of *cell in case of failure. *cell is assumed to be
469 at least cellLen chars */
470 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
471 struct ViceIoctl blob;
472 char tcell[MAX_PATH];
476 blob.out_size = MAX_PATH;
479 code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
482 strncpy(cell, tcell, cellLen);
483 cell[cellLen - 1] = '\0';
491 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
495 GetCPInfo(CP_ACP, &CodePageInfo);
497 if (CodePageInfo.MaxCharSize > 1)
498 // Only supporting non-Unicode strings
501 if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
503 // Looks like unicode, better translate it
504 // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
505 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
506 lpszOutputString, nOutStringLen-1, NULL, NULL);
507 lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
511 lpszOutputString[0] = '\0';
513 } // UnicodeStringToANSI
515 DWORD APIENTRY NPLogonNotify(
517 LPCWSTR lpAuthentInfoType,
518 LPVOID lpAuthentInfo,
519 LPCWSTR lpPreviousAuthentInfoType,
520 LPVOID lpPreviousAuthentInfo,
521 LPWSTR lpStationName,
522 LPVOID StationHandle,
523 LPWSTR *lpLogonScript)
525 char uname[MAX_USERNAME_LENGTH]="";
526 char password[MAX_PASSWORD_LENGTH]="";
527 char logonDomain[MAX_DOMAIN_LENGTH]="";
528 char cell[256]="<non-integrated logon>";
529 char homePath[MAX_PATH]="";
531 MSV1_0_INTERACTIVE_LOGON *IL;
541 DWORD LSPtype, LSPsize;
544 HWND hwndOwner = (HWND)StationHandle;
546 BOOLEAN afsWillAutoStart;
548 BOOLEAN uppercased_name = TRUE;
550 LogonOptions_t opt; /* domain specific logon options */
554 /* Initialize Logon Script to none */
557 /* TODO: We should check the value of lpAuthentInfoType before assuming that it is
558 MSV1_0_INTERACTIVE_LOGON though for our purposes KERB_INTERACTIVE_LOGON is
559 co-incidentally equivalent. */
560 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
562 /* Are we interactive? */
563 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
565 /* Convert from Unicode to ANSI */
567 /*TODO: Use SecureZeroMemory to erase passwords */
568 UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
569 UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
570 UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
572 /* Make sure AD-DOMANS sent from login that is sent to us is striped */
573 ctemp = strchr(uname, '@');
574 if (ctemp) *ctemp = 0;
576 /* is the name all uppercase? */
577 for ( ctemp = uname; *ctemp ; ctemp++) {
578 if ( islower(*ctemp) ) {
579 uppercased_name = FALSE;
584 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
585 0, KEY_QUERY_VALUE, &NPKey);
586 LSPsize=sizeof(TraceOption);
587 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
588 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
596 GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
597 retryInterval = opt.retryInterval;
598 sleepInterval = opt.sleepInterval;
599 *lpLogonScript = opt.logonScript;
601 DebugEvent("Got logon script: %S",opt.logonScript);
603 afsWillAutoStart = AFSWillAutoStart();
605 DebugEvent("LogonOption[%x], Service AutoStart[%d]",
606 opt.LogonOption,afsWillAutoStart);
608 /* Check for zero length password if integrated logon*/
609 if ( ISLOGONINTEGRATED(opt.LogonOption) ) {
610 if ( password[0] == 0 ) {
611 DebugEvent("Password is the empty string");
613 reason = "zero length password is illegal";
617 /* Get cell name if doing integrated logon.
618 We might overwrite this if we are logging into an AD realm and we find out that
619 the user's home dir is in some other cell. */
620 DebugEvent("About to call cm_GetRootCellName(%s)",cell);
621 code = cm_GetRootCellName(cell);
623 DebugEvent("Unable to obtain Root Cell");
625 reason = "unknown cell";
628 DebugEvent("Cell is %s",cell);
631 /* We get the user's home directory path, if applicable, though we can't lookup the
632 cell right away because the client service may not have started yet. This call
633 also sets the AD_REALM flag in opt.flags if applicable. */
634 if(ISREMOTE(opt.flags)) {
635 DebugEvent("Is Remote");
636 GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
640 /* loop until AFS is started. */
642 DebugEvent("while(TRUE) LogonOption[%x], Service AutoStart[%d]",
643 opt.LogonOption,afsWillAutoStart);
645 if(ISADREALM(opt.flags)) {
646 code = GetFileCellName(homePath,cell,256);
648 DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
650 /* Don't bail out if GetFileCellName failed.
651 * The home dir may not be in AFS after all.
656 /* if Integrated Logon */
657 if (ISLOGONINTEGRATED(opt.LogonOption))
659 if ( KFW_is_available() ) {
660 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
661 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",uname,opt.smbName,cell,code);
664 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
665 uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
667 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2","Code[%x]",
670 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && uppercased_name ) {
671 for ( ctemp = uname; *ctemp ; ctemp++) {
672 *ctemp = tolower(*ctemp);
674 uppercased_name = FALSE;
679 /*JUST check to see if its running*/
680 if (IsServiceRunning())
683 if (!afsWillAutoStart)
687 /* is service started yet?*/
688 DebugEvent("AFS AfsLogon - ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s]",
691 /* If we've failed because the client isn't running yet and the
692 * client is set to autostart (and therefore it makes sense for
693 * us to wait for it to start) then sleep a while and try again.
694 * If the error was something else, then give up. */
695 if (code != KTC_NOCM && code != KTC_NOCMRPC || !afsWillAutoStart)
698 /* If the retry interval has expired and we still aren't
699 * logged in, then just give up if we are not in interactive
700 * mode or the failSilently flag is set, otherwise let the
701 * user know we failed and give them a chance to try again. */
702 if (retryInterval <= 0) {
703 reason = "AFS not running";
704 if (!interactive || opt.failSilently)
706 flag = MessageBox(hwndOwner,
707 "AFS is still starting. Retry?",
709 MB_ICONQUESTION | MB_RETRYCANCEL);
710 if (flag == IDCANCEL)
713 /* Wait just a little while and try again */
714 retryInterval = sleepInterval = DEFAULT_SLEEP_INTERVAL;
717 if (retryInterval < sleepInterval)
718 sleepInterval = retryInterval;
720 Sleep(sleepInterval * 1000);
722 retryInterval -= sleepInterval;
725 DebugEvent("while loop exited");
726 /* remove any kerberos 5 tickets currently held by the SYSTEM account */
727 if ( KFW_is_available() )
728 KFW_AFS_destroy_tickets_for_cell(cell);
735 StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
737 if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
738 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
740 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
742 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
744 DeregisterEventSource(h);
746 code = MapAuthError(code);
749 if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
752 LocalFree(*lpLogonScript);
753 *lpLogonScript = NULL;
754 if (!afsWillAutoStart) // its not running, so if not autostart or integrated logon then just skip
760 if(opt.smbName) free(opt.smbName);
762 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
766 DWORD APIENTRY NPPasswordChangeNotify(
767 LPCWSTR lpAuthentInfoType,
768 LPVOID lpAuthentInfo,
769 LPCWSTR lpPreviousAuthentInfoType,
770 LPVOID lpPreviousAuthentInfo,
771 LPWSTR lpStationName,
772 LPVOID StationHandle,
775 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
781 #include <afs/vice.h>
782 #include <afs/fs_utils.h>
784 BOOL IsPathInAfs(const CHAR *strPath)
787 struct ViceIoctl blob;
791 blob.out_size = 2048;
794 code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
801 typedef struct _WLX_NOTIFICATION_INFO {
809 PFNMSGECALLBACK pStatusCallback;
810 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
813 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
815 DWORD LSPtype, LSPsize;
818 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
819 0, KEY_QUERY_VALUE, &NPKey);
820 LSPsize=sizeof(TraceOption);
821 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
822 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
825 DebugEvent0("AFS_Startup_Event");
828 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
831 TCHAR profileDir[256] = TEXT("");
833 PTOKEN_USER tokenUser = NULL;
837 DebugEvent0("AFS_Logoff_Event - Starting");
839 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
841 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
842 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
844 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
846 DebugEvent("GetTokenInformation failed: GLE = %lX", GetLastError());
851 /* We can't use pInfo->Domain for the domain since in the cross realm case
852 * this is source domain and not the destination domain.
854 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
855 WCHAR Domain[64]=L"";
856 GetLocalShortDomain(Domain);
857 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain))
858 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
861 if (strlen(profileDir)) {
862 DebugEvent("Profile Directory: %s", profileDir);
863 if (!IsPathInAfs(profileDir)) {
864 if (code = ktc_ForgetAllTokens())
865 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
867 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
869 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
872 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
876 LocalFree(tokenUser);