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 #include <WINNT\afsreg.h>
32 DWORD TraceOption = 0;
37 #define AFS_LOGON_EVENT_NAME TEXT("AFS Logon")
39 void DebugEvent0(char *a)
41 HANDLE h; char *ptbuf[1];
42 if (!ISLOGONTRACE(TraceOption))
44 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
46 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
47 DeregisterEventSource(h);
51 void DebugEvent(char *b,...)
53 HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
56 if (!ISLOGONTRACE(TraceOption))
59 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
61 StringCbVPrintf(buf, MAXBUF_+1,b,marker);
64 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
65 DeregisterEventSource(h);
69 static HANDLE hInitMutex = NULL;
70 static BOOL bInit = FALSE;
72 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
76 case DLL_PROCESS_ATTACH:
77 /* Initialization Mutex */
78 hInitMutex = CreateMutex(NULL, FALSE, NULL);
81 case DLL_PROCESS_DETACH:
82 CloseHandle(hInitMutex);
85 case DLL_THREAD_ATTACH:
86 case DLL_THREAD_DETACH:
88 /* Everything else succeeds but does nothing. */
95 void AfsLogonInit(void)
97 if ( bInit == FALSE ) {
98 if ( WaitForSingleObject( hInitMutex, INFINITE ) == WAIT_OBJECT_0 ) {
99 if ( bInit == FALSE ) {
105 ReleaseMutex(hInitMutex);
110 CHAR *GenRandomName(CHAR *pbuf)
113 srand( (unsigned)time( NULL ) );
114 for (i=0;i<MAXRANDOMNAMELEN-1;i++)
115 pbuf[i]='a'+(rand() % 26);
116 pbuf[MAXRANDOMNAMELEN-1]=0;
120 BOOLEAN AFSWillAutoStart(void)
125 BOOLEAN result = FALSE;
126 LPQUERY_SERVICE_CONFIG pConfig = NULL;
130 /* Open services manager */
131 scm = OpenSCManager(NULL, NULL, GENERIC_READ);
132 if (!scm) return FALSE;
134 /* Open AFSD service */
135 svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
139 /* Query AFSD service config, first just to get buffer size */
140 /* Expected to fail, so don't test return value */
141 (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
142 status = GetLastError();
143 if (status != ERROR_INSUFFICIENT_BUFFER)
146 /* Allocate buffer */
147 pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
151 /* Query AFSD service config, this time for real */
152 flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
156 /* Is it autostart? */
157 if (pConfig->dwStartType < SERVICE_DEMAND_START)
163 CloseServiceHandle(svc);
165 CloseServiceHandle(scm);
170 DWORD MapAuthError(DWORD code)
173 /* Unfortunately, returning WN_NO_NETWORK results in the MPR abandoning
174 * logon scripts for all credential managers, although they will still
175 * receive logon notifications. Since we don't want this, we return
176 * WN_SUCCESS. This is highly undesirable, but we also don't want to
177 * break other network providers.
181 return WN_NO_NETWORK; */
182 default: return WN_SUCCESS;
186 DWORD APIENTRY NPGetCaps(DWORD index)
190 /* Don't have our own type; use somebody else's. */
191 return WNNC_NET_SUN_PC_NFS;
194 /* Say we are already started, even though we might wait after we receive NPLogonNotify */
203 NetUserGetProfilePath( LPCWSTR Domain, LPCWSTR UserName, char * profilePath,
204 DWORD profilePathLen )
207 LPWSTR ServerName = NULL;
208 LPUSER_INFO_3 p3 = NULL;
210 NetGetAnyDCName(NULL, Domain, (LPBYTE *)&ServerName);
211 /* if NetGetAnyDCName fails, ServerName == NULL
212 * NetUserGetInfo will obtain local user information
214 code = NetUserGetInfo(ServerName, UserName, 3, (LPBYTE *)&p3);
215 if (code == NERR_Success)
217 code = NERR_UserNotFound;
219 if (p3->usri3_profile) {
220 DWORD len = lstrlenW(p3->usri3_profile);
222 /* Convert From Unicode to ANSI (UTF-8 for future) */
223 len = len < profilePathLen ? len : profilePathLen - 1;
224 WideCharToMultiByte(CP_UTF8, 0, p3->usri3_profile, len, profilePath, len, NULL, NULL);
225 profilePath[len] = '\0';
229 NetApiBufferFree(p3);
233 NetApiBufferFree(ServerName);
237 BOOL IsServiceRunning (void)
239 SERVICE_STATUS Status;
241 memset (&Status, 0x00, sizeof(Status));
242 Status.dwCurrentState = SERVICE_STOPPED;
244 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
247 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
249 QueryServiceStatus (hService, &Status);
250 CloseServiceHandle (hService);
253 CloseServiceHandle (hManager);
255 DebugEvent("AFS AfsLogon - Test Service Running","Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
256 return (Status.dwCurrentState == SERVICE_RUNNING);
259 BOOL IsServiceStartPending (void)
261 SERVICE_STATUS Status;
263 memset (&Status, 0x00, sizeof(Status));
264 Status.dwCurrentState = SERVICE_STOPPED;
266 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
269 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
271 QueryServiceStatus (hService, &Status);
272 CloseServiceHandle (hService);
275 CloseServiceHandle (hManager);
277 DebugEvent("AFS AfsLogon - Test Service Start Pending","Return Code[%x] ?Start Pending[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_START_PENDING));
278 return (Status.dwCurrentState == SERVICE_RUNNING);
281 /* LOOKUPKEYCHAIN: macro to look up the value in the list of keys in order until it's found
282 v:variable to receive value (reference type)
284 d:default, in case the value isn't on any of the keys
286 #define LOOKUPKEYCHAIN(v,t,d,n) \
288 rv = ~ERROR_SUCCESS; \
291 dwSize = sizeof(v); \
292 rv = RegQueryValueEx(hkDom, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
293 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDom with type [%d]", dwType); \
295 if(hkDoms && (rv != ERROR_SUCCESS || dwType != t)) { \
296 dwSize = sizeof(v); \
297 rv = RegQueryValueEx(hkDoms, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
298 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDoms with type [%d]", dwType); \
300 if(hkNp && (rv != ERROR_SUCCESS || dwType != t)) { \
301 dwSize = sizeof(v); \
302 rv = RegQueryValueEx(hkNp, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
303 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkNp with type [%d]", dwType); \
305 if(rv != ERROR_SUCCESS || dwType != t) { \
307 DebugEvent(#v " being set to default"); \
311 /* Get domain specific configuration info. We are returning void because if anything goes wrong
312 we just return defaults.
315 GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
316 HKEY hkParm = NULL; /* Service parameter */
317 HKEY hkNp = NULL; /* network provider key */
318 HKEY hkDoms = NULL; /* domains key */
319 HKEY hkDom = NULL; /* DOMAINS/domain key */
325 char computerName[MAX_COMPUTERNAME_LENGTH + 1];
328 memset(opt, 0, sizeof(LogonOptions_t));
330 DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
331 /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
332 opt->flags = LOGON_FLAG_REMOTE;
334 dwSize = MAX_COMPUTERNAME_LENGTH;
335 if(GetComputerName(computerName, &dwSize)) {
336 if(!stricmp(computerName, domain)) {
337 effDomain = "LOCALHOST";
338 opt->flags = LOGON_FLAG_LOCAL;
346 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, KEY_READ, &hkParm );
347 if(rv != ERROR_SUCCESS) {
349 DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
352 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PROVIDER_SUBKEY, 0, KEY_READ, &hkNp );
353 if(rv != ERROR_SUCCESS) {
355 DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
359 rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
360 if( rv != ERROR_SUCCESS ) {
362 DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
366 if(hkDoms && effDomain) {
367 rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
368 if( rv != ERROR_SUCCESS ) {
370 DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
371 /* If none of the domains match, we shouldn't use the domain key either */
376 DebugEvent("Not opening domain key for [%s]", effDomain);
378 /* Each individual can either be specified on the domain key, the domains key or in the
379 net provider key. They fail over in that order. If none is found, we just use the
383 LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
385 /* FailLoginsSilently */
386 dwSize = sizeof(dwDummy);
387 rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
388 if (rv != ERROR_SUCCESS)
389 LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
390 opt->failSilently = !!dwDummy;
393 LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
396 LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
398 opt->logonScript = NULL;
401 if(!ISLOGONINTEGRATED(opt->LogonOption)) {
402 goto cleanup; /* no need to lookup the logon script */
405 /* come up with SMB username */
406 if(ISHIGHSECURITY(opt->LogonOption)) {
407 opt->smbName = malloc( MAXRANDOMNAMELEN );
408 GenRandomName(opt->smbName);
410 /* username and domain for logon session is not necessarily the same as
411 username and domain passed into network provider. */
412 PSECURITY_LOGON_SESSION_DATA plsd;
413 char lsaUsername[MAX_USERNAME_LENGTH];
414 char lsaDomain[MAX_DOMAIN_LENGTH];
417 LsaGetLogonSessionData(lpLogonId, &plsd);
419 UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
420 UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
422 DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
424 if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
429 if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
436 opt->smbName = malloc(len);
438 StringCbCopy(opt->smbName, len, lsaDomain);
439 StringCbCat(opt->smbName, len, "\\");
440 StringCbCat(opt->smbName, len, lsaUsername);
442 strlwr(opt->smbName);
445 LsaFreeReturnBuffer(plsd);
448 DebugEvent("Looking up logon script");
450 /* First find out where the key is */
455 rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
456 if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
458 DebugEvent("Located logon script in hkDom");
461 rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
462 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
464 DebugEvent("Located logon script in hkDoms");
466 /* Note that the LogonScript in the NP key is only used if we are doing high security. */
467 else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
468 rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
469 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
471 DebugEvent("Located logon script in hkNp");
475 WCHAR *regscript = NULL;
476 WCHAR *regexscript = NULL;
477 WCHAR *regexuscript = NULL;
478 WCHAR *wuname = NULL;
483 StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
486 wuname = malloc(len * sizeof(WCHAR));
487 MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,len*sizeof(WCHAR));
489 DebugEvent("Username is set for [%S]", wuname);
491 /* dwSize still has the size of the required buffer in bytes. */
492 regscript = malloc(dwSize);
493 rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
494 if(rv != ERROR_SUCCESS) {/* what the ..? */
495 DebugEvent("Can't look up logon script [%d]",rv);
496 goto doneLogonScript;
499 DebugEvent("Found logon script [%S]", regscript);
501 if(dwType == REG_EXPAND_SZ) {
504 dwSize += MAX_PATH * sizeof(WCHAR); /* make room for environment expansion. */
505 regexscript = malloc(dwSize);
506 dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
508 regscript = regexscript;
510 if(dwReq > (dwSize / sizeof(WCHAR))) {
511 DebugEvent("Overflow while expanding environment strings.");
512 goto doneLogonScript;
516 DebugEvent("After expanding env strings [%S]", regscript);
518 if(wcsstr(regscript, L"%s")) {
519 dwSize += len * sizeof(WCHAR); /* make room for username expansion */
520 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
521 hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
523 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
524 hr = StringCbCopyW(regexuscript, dwSize, regscript);
527 DebugEvent("After expanding username [%S]", regexuscript);
530 opt->logonScript = regexuscript;
532 LocalFree(regexuscript);
535 if(wuname) free(wuname);
536 if(regscript) free(regscript);
537 if(regexscript) free(regexscript);
540 DebugEvent("Looking up TheseCells");
542 /* First find out where the key is */
547 rv = RegQueryValueEx(hkDom, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
548 if (rv == ERROR_SUCCESS && dwType == REG_MULTI_SZ) {
550 DebugEvent("Located TheseCells in hkDom");
552 rv = RegQueryValueEx(hkDoms, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
553 if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
555 DebugEvent("Located TheseCells in hkDoms");
557 rv = RegQueryValueEx(hkNp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
558 if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
560 DebugEvent("Located TheseCells in hkNp");
568 /* dwSize still has the size of the required buffer in bytes. */
569 thesecells = malloc(dwSize);
570 rv = RegQueryValueEx(hkTemp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, (LPBYTE) thesecells, &dwSize);
571 if(rv != ERROR_SUCCESS) {/* what the ..? */
572 DebugEvent("Can't look up TheseCells [%d]",rv);
576 DebugEvent("Found TheseCells [%s]", thesecells);
577 opt->theseCells = thesecells;
583 if(hkNp) RegCloseKey(hkNp);
584 if(hkDom) RegCloseKey(hkDom);
585 if(hkDoms) RegCloseKey(hkDoms);
586 if(hkParm) RegCloseKey(hkParm);
589 #undef LOOKUPKEYCHAIN
591 /* Try to find out which cell the given path is in. We must retain
592 the contents of *cell in case of failure. *cell is assumed to be
593 at least cellLen chars */
594 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
595 struct ViceIoctl blob;
596 char tcell[MAX_PATH];
600 blob.out_size = MAX_PATH;
603 code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
606 strncpy(cell, tcell, cellLen);
607 cell[cellLen - 1] = '\0';
615 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
619 GetCPInfo(CP_ACP, &CodePageInfo);
621 if (CodePageInfo.MaxCharSize > 1)
622 // Only supporting non-Unicode strings
625 if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
627 // Looks like unicode, better translate it
628 // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
629 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
630 lpszOutputString, nOutStringLen-1, NULL, NULL);
631 lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
635 lpszOutputString[0] = '\0';
637 } // UnicodeStringToANSI
639 DWORD APIENTRY NPLogonNotify(
641 LPCWSTR lpAuthentInfoType,
642 LPVOID lpAuthentInfo,
643 LPCWSTR lpPreviousAuthentInfoType,
644 LPVOID lpPreviousAuthentInfo,
645 LPWSTR lpStationName,
646 LPVOID StationHandle,
647 LPWSTR *lpLogonScript)
649 char uname[MAX_USERNAME_LENGTH]="";
650 char password[MAX_PASSWORD_LENGTH]="";
651 char logonDomain[MAX_DOMAIN_LENGTH]="";
652 char cell[256]="<non-integrated logon>";
653 char homePath[MAX_PATH]="";
655 MSV1_0_INTERACTIVE_LOGON *IL;
665 DWORD LSPtype, LSPsize;
668 HWND hwndOwner = (HWND)StationHandle;
670 BOOLEAN afsWillAutoStart;
672 BOOLEAN lowercased_name = TRUE;
674 LogonOptions_t opt; /* domain specific logon options */
678 /* Make sure the AFS Libraries are initialized */
681 /* Initialize Logon Script to none */
684 /* TODO: We should check the value of lpAuthentInfoType before assuming that it is
685 MSV1_0_INTERACTIVE_LOGON though for our purposes KERB_INTERACTIVE_LOGON is
686 co-incidentally equivalent. */
687 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
689 /* Are we interactive? */
690 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
692 /* Convert from Unicode to ANSI */
694 /*TODO: Use SecureZeroMemory to erase passwords */
695 UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
696 UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
697 UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
699 /* Make sure AD-DOMANS sent from login that is sent to us is striped */
700 ctemp = strchr(uname, '@');
701 if (ctemp) *ctemp = 0;
703 /* is the name all lowercase? */
704 for ( ctemp = uname; *ctemp ; ctemp++) {
705 if ( !islower(*ctemp) ) {
706 lowercased_name = FALSE;
711 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
712 0, KEY_QUERY_VALUE, &NPKey);
713 LSPsize=sizeof(TraceOption);
714 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
715 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
723 GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
724 retryInterval = opt.retryInterval;
725 sleepInterval = opt.sleepInterval;
726 *lpLogonScript = opt.logonScript;
728 if (retryInterval < sleepInterval)
729 sleepInterval = retryInterval;
731 DebugEvent("Got logon script: %S",opt.logonScript);
733 afsWillAutoStart = AFSWillAutoStart();
735 DebugEvent("LogonOption[%x], Service AutoStart[%d]",
736 opt.LogonOption,afsWillAutoStart);
738 /* Check for zero length password if integrated logon*/
739 if ( ISLOGONINTEGRATED(opt.LogonOption) ) {
740 if ( password[0] == 0 ) {
741 DebugEvent("Password is the empty string");
743 reason = "zero length password is illegal";
747 /* Get cell name if doing integrated logon.
748 We might overwrite this if we are logging into an AD realm and we find out that
749 the user's home dir is in some other cell. */
750 DebugEvent("About to call cm_GetRootCellName(%s)",cell);
751 code = cm_GetRootCellName(cell);
753 DebugEvent("Unable to obtain Root Cell");
755 reason = "unknown cell";
758 DebugEvent("Cell is %s",cell);
761 /* We get the user's home directory path, if applicable, though we can't lookup the
762 cell right away because the client service may not have started yet. This call
763 also sets the AD_REALM flag in opt.flags if applicable. */
764 if (ISREMOTE(opt.flags)) {
765 DebugEvent("Is Remote");
766 GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
770 /* loop until AFS is started. */
772 DebugEvent("while(TRUE) LogonOption[%x], Service AutoStart[%d]",
773 opt.LogonOption,afsWillAutoStart);
775 if (ISADREALM(opt.flags)) {
776 code = GetFileCellName(homePath,cell,256);
778 DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
780 /* Don't bail out if GetFileCellName failed.
781 * The home dir may not be in AFS after all.
786 /* if Integrated Logon */
787 if (ISLOGONINTEGRATED(opt.LogonOption))
789 if ( KFW_is_available() ) {
790 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
791 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",uname,opt.smbName,cell,code);
792 if (code == 0 && opt.theseCells) {
793 char * principal, *p;
795 principal = (char *)malloc(strlen(uname) + strlen(cell) + 2);
797 strcpy(principal, uname);
798 p = principal + strlen(uname);
807 code = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
808 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
809 principal,opt.smbName,p,code);
817 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
818 uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
820 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s]",
823 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
824 for ( ctemp = uname; *ctemp ; ctemp++) {
825 *ctemp = tolower(*ctemp);
827 lowercased_name = TRUE;
831 /* is service started yet?*/
833 /* If we've failed because the client isn't running yet and the
834 * client is set to autostart (and therefore it makes sense for
835 * us to wait for it to start) then sleep a while and try again.
836 * If the error was something else, then give up. */
837 if (code != KTC_NOCM && code != KTC_NOCMRPC || !afsWillAutoStart)
841 /*JUST check to see if its running*/
842 if (IsServiceRunning())
844 if (afsWillAutoStart && !IsServiceStartPending()) {
846 reason = "AFS Service start failed";
851 /* If the retry interval has expired and we still aren't
852 * logged in, then just give up if we are not in interactive
853 * mode or the failSilently flag is set, otherwise let the
854 * user know we failed and give them a chance to try again. */
855 if (retryInterval <= 0) {
856 reason = "AFS not running";
857 if (!interactive || opt.failSilently)
859 flag = MessageBox(hwndOwner,
860 "AFS is still starting. Retry?",
862 MB_ICONQUESTION | MB_RETRYCANCEL);
863 if (flag == IDCANCEL)
866 /* Wait just a little while and try again */
867 retryInterval = opt.retryInterval;
871 Sleep(sleepInterval * 1000);
872 retryInterval -= sleepInterval;
875 DebugEvent("while loop exited");
876 /* remove any kerberos 5 tickets currently held by the SYSTEM account */
877 if ( KFW_is_available() )
878 KFW_AFS_destroy_tickets_for_cell(cell);
885 StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
887 if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
888 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
890 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
892 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
894 DeregisterEventSource(h);
896 code = MapAuthError(code);
899 if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
902 LocalFree(*lpLogonScript);
903 *lpLogonScript = NULL;
904 if (!afsWillAutoStart) // its not running, so if not autostart or integrated logon then just skip
909 if (opt.theseCells) free(opt.theseCells);
910 if (opt.smbName) free(opt.smbName);
912 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
916 DWORD APIENTRY NPPasswordChangeNotify(
917 LPCWSTR lpAuthentInfoType,
918 LPVOID lpAuthentInfo,
919 LPCWSTR lpPreviousAuthentInfoType,
920 LPVOID lpPreviousAuthentInfo,
921 LPWSTR lpStationName,
922 LPVOID StationHandle,
925 /* Make sure the AFS Libraries are initialized */
928 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
934 #include <afs/vice.h>
935 #include <afs/fs_utils.h>
937 BOOL IsPathInAfs(const CHAR *strPath)
940 struct ViceIoctl blob;
944 blob.out_size = 2048;
947 code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
954 typedef struct _WLX_NOTIFICATION_INFO {
962 PFNMSGECALLBACK pStatusCallback;
963 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
966 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
968 DWORD LSPtype, LSPsize;
971 /* Make sure the AFS Libraries are initialized */
974 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
975 0, KEY_QUERY_VALUE, &NPKey);
976 LSPsize=sizeof(TraceOption);
977 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
978 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
981 DebugEvent0("AFS_Startup_Event");
984 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
987 TCHAR profileDir[1024] = TEXT("");
989 PTOKEN_USER tokenUser = NULL;
993 /* Make sure the AFS Libraries are initialized */
996 DebugEvent0("AFS_Logoff_Event - Starting");
998 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1000 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1001 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1003 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1005 DebugEvent("GetTokenInformation failed: GLE = %lX", GetLastError());
1010 /* We can't use pInfo->Domain for the domain since in the cross realm case
1011 * this is source domain and not the destination domain.
1013 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1014 WCHAR Domain[64]=L"";
1015 GetLocalShortDomain(Domain, sizeof(Domain));
1016 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1017 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1018 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1022 if (strlen(profileDir)) {
1023 DebugEvent("Profile Directory: %s", profileDir);
1024 if (!IsPathInAfs(profileDir)) {
1025 if (code = ktc_ForgetAllTokens())
1026 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1028 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1030 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1033 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1037 LocalFree(tokenUser);