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 BOOL IsServiceStartPending (void)
259 SERVICE_STATUS Status;
261 memset (&Status, 0x00, sizeof(Status));
262 Status.dwCurrentState = SERVICE_STOPPED;
264 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
267 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
269 QueryServiceStatus (hService, &Status);
270 CloseServiceHandle (hService);
273 CloseServiceHandle (hManager);
275 DebugEvent("AFS AfsLogon - Test Service Start Pending","Return Code[%x] ?Start Pending[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_START_PENDING));
276 return (Status.dwCurrentState == SERVICE_RUNNING);
279 /* LOOKUPKEYCHAIN: macro to look up the value in the list of keys in order until it's found
280 v:variable to receive value (reference type)
282 d:default, in case the value isn't on any of the keys
284 #define LOOKUPKEYCHAIN(v,t,d,n) \
286 rv = ~ERROR_SUCCESS; \
289 dwSize = sizeof(v); \
290 rv = RegQueryValueEx(hkDom, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
291 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDom with type [%d]", dwType); \
293 if(hkDoms && (rv != ERROR_SUCCESS || dwType != t)) { \
294 dwSize = sizeof(v); \
295 rv = RegQueryValueEx(hkDoms, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
296 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDoms with type [%d]", dwType); \
298 if(hkNp && (rv != ERROR_SUCCESS || dwType != t)) { \
299 dwSize = sizeof(v); \
300 rv = RegQueryValueEx(hkNp, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
301 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkNp with type [%d]", dwType); \
303 if(rv != ERROR_SUCCESS || dwType != t) { \
305 DebugEvent(#v " being set to default"); \
309 /* Get domain specific configuration info. We are returning void because if anything goes wrong
310 we just return defaults.
313 GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
314 HKEY hkParm = NULL; /* Service parameter */
315 HKEY hkNp = NULL; /* network provider key */
316 HKEY hkDoms = NULL; /* domains key */
317 HKEY hkDom = NULL; /* DOMAINS/domain key */
323 char computerName[MAX_COMPUTERNAME_LENGTH + 1];
326 DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
327 /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
328 opt->flags = LOGON_FLAG_REMOTE;
330 dwSize = MAX_COMPUTERNAME_LENGTH;
331 if(GetComputerName(computerName, &dwSize)) {
332 if(!stricmp(computerName, domain)) {
333 effDomain = "LOCALHOST";
334 opt->flags = LOGON_FLAG_LOCAL;
342 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY, 0, KEY_READ, &hkParm );
343 if(rv != ERROR_SUCCESS) {
345 DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
348 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CLIENT_PROVIDER_KEY, 0, KEY_READ, &hkNp );
349 if(rv != ERROR_SUCCESS) {
351 DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
355 rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
356 if( rv != ERROR_SUCCESS ) {
358 DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
362 if(hkDoms && effDomain) {
363 rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
364 if( rv != ERROR_SUCCESS ) {
366 DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
367 /* If none of the domains match, we shouldn't use the domain key either */
372 DebugEvent("Not opening domain key for [%s]", effDomain);
374 /* Each individual can either be specified on the domain key, the domains key or in the
375 net provider key. They fail over in that order. If none is found, we just use the
379 LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
381 /* FailLoginsSilently */
382 dwSize = sizeof(dwDummy);
383 rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
384 if (rv != ERROR_SUCCESS)
385 LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
386 opt->failSilently = !!dwDummy;
389 LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
392 LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
394 opt->logonScript = NULL;
397 if(!ISLOGONINTEGRATED(opt->LogonOption)) {
398 goto cleanup; /* no need to lookup the logon script */
401 /* come up with SMB username */
402 if(ISHIGHSECURITY(opt->LogonOption)) {
403 opt->smbName = malloc( MAXRANDOMNAMELEN );
404 GenRandomName(opt->smbName);
406 /* username and domain for logon session is not necessarily the same as
407 username and domain passed into network provider. */
408 PSECURITY_LOGON_SESSION_DATA plsd;
409 char lsaUsername[MAX_USERNAME_LENGTH];
410 char lsaDomain[MAX_DOMAIN_LENGTH];
413 LsaGetLogonSessionData(lpLogonId, &plsd);
415 UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
416 UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
418 DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
420 if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
425 if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
432 opt->smbName = malloc(len);
434 StringCbCopy(opt->smbName, len, lsaDomain);
435 StringCbCat(opt->smbName, len, "\\");
436 StringCbCat(opt->smbName, len, lsaUsername);
438 strlwr(opt->smbName);
441 LsaFreeReturnBuffer(plsd);
444 DebugEvent("Looking up logon script");
446 /* First find out where the key is */
451 rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
452 if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
454 DebugEvent("Located logon script in hkDom");
457 rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
458 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
460 DebugEvent("Located logon script in hkDoms");
462 /* Note that the LogonScript in the NP key is only used if we are doing high security. */
463 else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
464 rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
465 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
467 DebugEvent("Located logon script in hkNp");
471 WCHAR *regscript = NULL;
472 WCHAR *regexscript = NULL;
473 WCHAR *regexuscript = NULL;
474 WCHAR *wuname = NULL;
479 StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
482 wuname = malloc(len * sizeof(WCHAR));
483 MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,len*sizeof(WCHAR));
485 DebugEvent("Username is set for [%S]", wuname);
487 /* dwSize still has the size of the required buffer in bytes. */
488 regscript = malloc(dwSize);
489 rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
490 if(rv != ERROR_SUCCESS) {/* what the ..? */
491 DebugEvent("Can't look up logon script [%d]",rv);
492 goto doneLogonScript;
495 DebugEvent("Found logon script [%S]", regscript);
497 if(dwType == REG_EXPAND_SZ) {
500 dwSize += MAX_PATH * sizeof(WCHAR); /* make room for environment expansion. */
501 regexscript = malloc(dwSize);
502 dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
504 regscript = regexscript;
506 if(dwReq > (dwSize / sizeof(WCHAR))) {
507 DebugEvent("Overflow while expanding environment strings.");
508 goto doneLogonScript;
512 DebugEvent("After expanding env strings [%S]", regscript);
514 if(wcsstr(regscript, L"%s")) {
515 dwSize += len * sizeof(WCHAR); /* make room for username expansion */
516 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
517 hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
519 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
520 hr = StringCbCopyW(regexuscript, dwSize, regscript);
523 DebugEvent("After expanding username [%S]", regexuscript);
526 opt->logonScript = regexuscript;
528 LocalFree(regexuscript);
531 if(wuname) free(wuname);
532 if(regscript) free(regscript);
533 if(regexscript) free(regexscript);
537 if(hkNp) RegCloseKey(hkNp);
538 if(hkDom) RegCloseKey(hkDom);
539 if(hkDoms) RegCloseKey(hkDoms);
540 if(hkParm) RegCloseKey(hkParm);
543 #undef LOOKUPKEYCHAIN
545 /* Try to find out which cell the given path is in. We must retain
546 the contents of *cell in case of failure. *cell is assumed to be
547 at least cellLen chars */
548 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
549 struct ViceIoctl blob;
550 char tcell[MAX_PATH];
554 blob.out_size = MAX_PATH;
557 code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
560 strncpy(cell, tcell, cellLen);
561 cell[cellLen - 1] = '\0';
569 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
573 GetCPInfo(CP_ACP, &CodePageInfo);
575 if (CodePageInfo.MaxCharSize > 1)
576 // Only supporting non-Unicode strings
579 if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
581 // Looks like unicode, better translate it
582 // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
583 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
584 lpszOutputString, nOutStringLen-1, NULL, NULL);
585 lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
589 lpszOutputString[0] = '\0';
591 } // UnicodeStringToANSI
593 DWORD APIENTRY NPLogonNotify(
595 LPCWSTR lpAuthentInfoType,
596 LPVOID lpAuthentInfo,
597 LPCWSTR lpPreviousAuthentInfoType,
598 LPVOID lpPreviousAuthentInfo,
599 LPWSTR lpStationName,
600 LPVOID StationHandle,
601 LPWSTR *lpLogonScript)
603 char uname[MAX_USERNAME_LENGTH]="";
604 char password[MAX_PASSWORD_LENGTH]="";
605 char logonDomain[MAX_DOMAIN_LENGTH]="";
606 char cell[256]="<non-integrated logon>";
607 char homePath[MAX_PATH]="";
609 MSV1_0_INTERACTIVE_LOGON *IL;
619 DWORD LSPtype, LSPsize;
622 HWND hwndOwner = (HWND)StationHandle;
624 BOOLEAN afsWillAutoStart;
626 BOOLEAN lowercased_name = TRUE;
628 LogonOptions_t opt; /* domain specific logon options */
632 /* Make sure the AFS Libraries are initialized */
635 /* Initialize Logon Script to none */
638 /* TODO: We should check the value of lpAuthentInfoType before assuming that it is
639 MSV1_0_INTERACTIVE_LOGON though for our purposes KERB_INTERACTIVE_LOGON is
640 co-incidentally equivalent. */
641 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
643 /* Are we interactive? */
644 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
646 /* Convert from Unicode to ANSI */
648 /*TODO: Use SecureZeroMemory to erase passwords */
649 UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
650 UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
651 UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
653 /* Make sure AD-DOMANS sent from login that is sent to us is striped */
654 ctemp = strchr(uname, '@');
655 if (ctemp) *ctemp = 0;
657 /* is the name all lowercase? */
658 for ( ctemp = uname; *ctemp ; ctemp++) {
659 if ( !islower(*ctemp) ) {
660 lowercased_name = FALSE;
665 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
666 0, KEY_QUERY_VALUE, &NPKey);
667 LSPsize=sizeof(TraceOption);
668 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
669 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
677 GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
678 retryInterval = opt.retryInterval;
679 sleepInterval = opt.sleepInterval;
680 *lpLogonScript = opt.logonScript;
682 if (retryInterval < sleepInterval)
683 sleepInterval = retryInterval;
685 DebugEvent("Got logon script: %S",opt.logonScript);
687 afsWillAutoStart = AFSWillAutoStart();
689 DebugEvent("LogonOption[%x], Service AutoStart[%d]",
690 opt.LogonOption,afsWillAutoStart);
692 /* Check for zero length password if integrated logon*/
693 if ( ISLOGONINTEGRATED(opt.LogonOption) ) {
694 if ( password[0] == 0 ) {
695 DebugEvent("Password is the empty string");
697 reason = "zero length password is illegal";
701 /* Get cell name if doing integrated logon.
702 We might overwrite this if we are logging into an AD realm and we find out that
703 the user's home dir is in some other cell. */
704 DebugEvent("About to call cm_GetRootCellName(%s)",cell);
705 code = cm_GetRootCellName(cell);
707 DebugEvent("Unable to obtain Root Cell");
709 reason = "unknown cell";
712 DebugEvent("Cell is %s",cell);
715 /* We get the user's home directory path, if applicable, though we can't lookup the
716 cell right away because the client service may not have started yet. This call
717 also sets the AD_REALM flag in opt.flags if applicable. */
718 if (ISREMOTE(opt.flags)) {
719 DebugEvent("Is Remote");
720 GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
724 /* loop until AFS is started. */
726 DebugEvent("while(TRUE) LogonOption[%x], Service AutoStart[%d]",
727 opt.LogonOption,afsWillAutoStart);
729 if (ISADREALM(opt.flags)) {
730 code = GetFileCellName(homePath,cell,256);
732 DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
734 /* Don't bail out if GetFileCellName failed.
735 * The home dir may not be in AFS after all.
740 /* if Integrated Logon */
741 if (ISLOGONINTEGRATED(opt.LogonOption))
743 if ( KFW_is_available() ) {
744 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
745 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
746 uname,opt.smbName,cell,code);
748 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
749 uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
752 DebugEvent("AFS AfsLogon - ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s] Reason[%s]",
753 code,uname,cell,reason ? reason : "<none>");
756 sprintf(msg, "Code[%x] uname[%s] Cell[%s] Reason[%s]",
757 code,uname,cell,reason ? reason : "<none>");
758 MessageBox(hwndOwner,
761 MB_ICONINFORMATION | MB_OK);
764 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
765 for ( ctemp = uname; *ctemp ; ctemp++) {
766 *ctemp = tolower(*ctemp);
768 lowercased_name = TRUE;
772 /* is service started yet?*/
773 /* If we've failed because the client isn't running yet and the
774 * client is set to autostart (and therefore it makes sense for
775 * us to wait for it to start) then sleep a while and try again.
776 * If the error was something else, then give up. */
777 if (code != KTC_NOCM && code != KTC_NOCMRPC || !afsWillAutoStart)
780 /*JUST check to see if its running*/
781 if (IsServiceRunning())
783 if (afsWillAutoStart && !IsServiceStartPending()) {
785 reason = "AFS Service start failed";
790 /* If the retry interval has expired and we still aren't
791 * logged in, then just give up if we are not in interactive
792 * mode or the failSilently flag is set, otherwise let the
793 * user know we failed and give them a chance to try again. */
794 if (retryInterval <= 0) {
795 reason = "AFS not running";
796 if (!interactive || opt.failSilently)
798 flag = MessageBox(hwndOwner,
799 "AFS is still starting. Retry?",
801 MB_ICONQUESTION | MB_RETRYCANCEL);
802 if (flag == IDCANCEL)
805 /* Wait just a little while and try again */
806 retryInterval = opt.retryInterval;
810 Sleep(sleepInterval * 1000);
811 retryInterval -= sleepInterval;
814 DebugEvent("while loop exited");
815 /* remove any kerberos 5 tickets currently held by the SYSTEM account */
816 if ( KFW_is_available() )
817 KFW_AFS_destroy_tickets_for_cell(cell);
824 StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
826 if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
827 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
829 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
831 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
833 DeregisterEventSource(h);
835 code = MapAuthError(code);
838 if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
841 LocalFree(*lpLogonScript);
842 *lpLogonScript = NULL;
843 if (!afsWillAutoStart) // its not running, so if not autostart or integrated logon then just skip
848 if(opt.smbName) free(opt.smbName);
850 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
854 DWORD APIENTRY NPPasswordChangeNotify(
855 LPCWSTR lpAuthentInfoType,
856 LPVOID lpAuthentInfo,
857 LPCWSTR lpPreviousAuthentInfoType,
858 LPVOID lpPreviousAuthentInfo,
859 LPWSTR lpStationName,
860 LPVOID StationHandle,
863 /* Make sure the AFS Libraries are initialized */
866 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
872 #include <afs/vice.h>
873 #include <afs/fs_utils.h>
875 BOOL IsPathInAfs(const CHAR *strPath)
878 struct ViceIoctl blob;
882 blob.out_size = 2048;
885 code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
892 typedef struct _WLX_NOTIFICATION_INFO {
900 PFNMSGECALLBACK pStatusCallback;
901 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
904 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
906 DWORD LSPtype, LSPsize;
909 /* Make sure the AFS Libraries are initialized */
912 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
913 0, KEY_QUERY_VALUE, &NPKey);
914 LSPsize=sizeof(TraceOption);
915 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
916 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
919 DebugEvent0("AFS_Startup_Event");
922 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
925 TCHAR profileDir[1024] = TEXT("");
927 PTOKEN_USER tokenUser = NULL;
931 /* Make sure the AFS Libraries are initialized */
934 DebugEvent0("AFS_Logoff_Event - Starting");
936 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
938 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
939 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
941 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
943 DebugEvent("GetTokenInformation failed: GLE = %lX", GetLastError());
948 /* We can't use pInfo->Domain for the domain since in the cross realm case
949 * this is source domain and not the destination domain.
951 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
952 WCHAR Domain[64]=L"";
953 GetLocalShortDomain(Domain, sizeof(Domain));
954 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
955 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
956 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
960 if (strlen(profileDir)) {
961 DebugEvent("Profile Directory: %s", profileDir);
962 if (!IsPathInAfs(profileDir)) {
963 if (code = ktc_ForgetAllTokens())
964 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
966 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
968 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
971 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
975 LocalFree(tokenUser);