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>
21 #include <afs/param.h>
23 #include <afs/pioctl_nt.h>
24 #include <afs/kautils.h>
27 #include "cm_config.h"
30 #include "lanahelper.h"
32 #include <WINNT\afsreg.h>
34 DWORD TraceOption = 0;
39 #define AFS_LOGON_EVENT_NAME TEXT("AFS Logon")
41 void DebugEvent0(char *a)
43 HANDLE h; char *ptbuf[1];
44 if (!ISLOGONTRACE(TraceOption))
46 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
48 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
49 DeregisterEventSource(h);
53 void DebugEvent(char *b,...)
55 HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
58 if (!ISLOGONTRACE(TraceOption))
61 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
63 StringCbVPrintf(buf, MAXBUF_+1,b,marker);
66 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
67 DeregisterEventSource(h);
71 static HANDLE hInitMutex = NULL;
72 static BOOL bInit = FALSE;
74 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
78 case DLL_PROCESS_ATTACH:
79 /* Initialization Mutex */
80 hInitMutex = CreateMutex(NULL, FALSE, NULL);
83 case DLL_PROCESS_DETACH:
84 CloseHandle(hInitMutex);
87 case DLL_THREAD_ATTACH:
88 case DLL_THREAD_DETACH:
90 /* Everything else succeeds but does nothing. */
97 void AfsLogonInit(void)
99 if ( bInit == FALSE ) {
100 if ( WaitForSingleObject( hInitMutex, INFINITE ) == WAIT_OBJECT_0 ) {
101 if ( bInit == FALSE ) {
107 ReleaseMutex(hInitMutex);
112 CHAR *GenRandomName(CHAR *pbuf)
115 srand( (unsigned)time( NULL ) );
116 for (i=0;i<MAXRANDOMNAMELEN-1;i++)
117 pbuf[i]='a'+(rand() % 26);
118 pbuf[MAXRANDOMNAMELEN-1]=0;
122 BOOLEAN AFSWillAutoStart(void)
127 BOOLEAN result = FALSE;
128 LPQUERY_SERVICE_CONFIG pConfig = NULL;
132 /* Open services manager */
133 scm = OpenSCManager(NULL, NULL, GENERIC_READ);
134 if (!scm) return FALSE;
136 /* Open AFSD service */
137 svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
141 /* Query AFSD service config, first just to get buffer size */
142 /* Expected to fail, so don't test return value */
143 (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
144 status = GetLastError();
145 if (status != ERROR_INSUFFICIENT_BUFFER)
148 /* Allocate buffer */
149 pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
153 /* Query AFSD service config, this time for real */
154 flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
158 /* Is it autostart? */
159 if (pConfig->dwStartType < SERVICE_DEMAND_START)
165 CloseServiceHandle(svc);
167 CloseServiceHandle(scm);
172 DWORD MapAuthError(DWORD code)
175 /* Unfortunately, returning WN_NO_NETWORK results in the MPR abandoning
176 * logon scripts for all credential managers, although they will still
177 * receive logon notifications. Since we don't want this, we return
178 * WN_SUCCESS. This is highly undesirable, but we also don't want to
179 * break other network providers.
183 return WN_NO_NETWORK; */
184 default: return WN_SUCCESS;
188 DWORD APIENTRY NPGetCaps(DWORD index)
192 /* Don't have our own type; use somebody else's. */
193 return WNNC_NET_SUN_PC_NFS;
196 /* Say we are already started, even though we might wait after we receive NPLogonNotify */
205 NetUserGetProfilePath( LPCWSTR Domain, LPCWSTR UserName, char * profilePath,
206 DWORD profilePathLen )
209 LPWSTR ServerName = NULL;
210 LPUSER_INFO_3 p3 = NULL;
212 NetGetAnyDCName(NULL, Domain, (LPBYTE *)&ServerName);
213 /* if NetGetAnyDCName fails, ServerName == NULL
214 * NetUserGetInfo will obtain local user information
216 code = NetUserGetInfo(ServerName, UserName, 3, (LPBYTE *)&p3);
217 if (code == NERR_Success)
219 code = NERR_UserNotFound;
221 if (p3->usri3_profile) {
222 DWORD len = lstrlenW(p3->usri3_profile);
224 /* Convert From Unicode to ANSI (UTF-8 for future) */
225 len = len < profilePathLen ? len : profilePathLen - 1;
226 WideCharToMultiByte(CP_UTF8, 0, p3->usri3_profile, len, profilePath, len, NULL, NULL);
227 profilePath[len] = '\0';
231 NetApiBufferFree(p3);
235 NetApiBufferFree(ServerName);
239 BOOL IsServiceRunning (void)
241 SERVICE_STATUS Status;
243 memset (&Status, 0x00, sizeof(Status));
244 Status.dwCurrentState = SERVICE_STOPPED;
246 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
249 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
251 QueryServiceStatus (hService, &Status);
252 CloseServiceHandle (hService);
255 CloseServiceHandle (hManager);
257 DebugEvent("AFS AfsLogon - Test Service Running","Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
258 return (Status.dwCurrentState == SERVICE_RUNNING);
261 BOOL IsServiceStartPending (void)
263 SERVICE_STATUS Status;
265 memset (&Status, 0x00, sizeof(Status));
266 Status.dwCurrentState = SERVICE_STOPPED;
268 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
271 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
273 QueryServiceStatus (hService, &Status);
274 CloseServiceHandle (hService);
277 CloseServiceHandle (hManager);
279 DebugEvent("AFS AfsLogon - Test Service Start Pending","Return Code[%x] ?Start Pending[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_START_PENDING));
280 return (Status.dwCurrentState == SERVICE_RUNNING);
283 /* LOOKUPKEYCHAIN: macro to look up the value in the list of keys in order until it's found
284 v:variable to receive value (reference type)
286 d:default, in case the value isn't on any of the keys
288 #define LOOKUPKEYCHAIN(v,t,d,n) \
290 rv = ~ERROR_SUCCESS; \
293 dwSize = sizeof(v); \
294 rv = RegQueryValueEx(hkDom, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
295 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDom with type [%d]", dwType); \
297 if(hkDoms && (rv != ERROR_SUCCESS || dwType != t)) { \
298 dwSize = sizeof(v); \
299 rv = RegQueryValueEx(hkDoms, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
300 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDoms with type [%d]", dwType); \
302 if(hkNp && (rv != ERROR_SUCCESS || dwType != t)) { \
303 dwSize = sizeof(v); \
304 rv = RegQueryValueEx(hkNp, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
305 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkNp with type [%d]", dwType); \
307 if(rv != ERROR_SUCCESS || dwType != t) { \
309 DebugEvent(#v " being set to default"); \
313 /* Get domain specific configuration info. We are returning void because if anything goes wrong
314 we just return defaults.
317 GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
318 HKEY hkParm = NULL; /* Service parameter */
319 HKEY hkNp = NULL; /* network provider key */
320 HKEY hkDoms = NULL; /* domains key */
321 HKEY hkDom = NULL; /* DOMAINS/domain key */
327 char computerName[MAX_COMPUTERNAME_LENGTH + 1];
330 memset(opt, 0, sizeof(LogonOptions_t));
332 DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
333 /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
334 opt->flags = LOGON_FLAG_REMOTE;
336 dwSize = MAX_COMPUTERNAME_LENGTH;
337 if(GetComputerName(computerName, &dwSize)) {
338 if(!stricmp(computerName, domain)) {
339 effDomain = "LOCALHOST";
340 opt->flags = LOGON_FLAG_LOCAL;
348 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, KEY_READ, &hkParm );
349 if(rv != ERROR_SUCCESS) {
351 DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
354 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PROVIDER_SUBKEY, 0, KEY_READ, &hkNp );
355 if(rv != ERROR_SUCCESS) {
357 DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
361 rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
362 if( rv != ERROR_SUCCESS ) {
364 DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
368 if(hkDoms && effDomain) {
369 rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
370 if( rv != ERROR_SUCCESS ) {
372 DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
373 /* If none of the domains match, we shouldn't use the domain key either */
378 DebugEvent("Not opening domain key for [%s]", effDomain);
380 /* Each individual can either be specified on the domain key, the domains key or in the
381 net provider key. They fail over in that order. If none is found, we just use the
385 LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
387 /* FailLoginsSilently */
388 dwSize = sizeof(dwDummy);
389 rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
390 if (rv != ERROR_SUCCESS)
391 LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
392 opt->failSilently = !!dwDummy;
395 LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
398 LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
400 opt->logonScript = NULL;
403 if(!ISLOGONINTEGRATED(opt->LogonOption)) {
404 goto cleanup; /* no need to lookup the logon script */
407 /* come up with SMB username */
408 if(ISHIGHSECURITY(opt->LogonOption)) {
409 opt->smbName = malloc( MAXRANDOMNAMELEN );
410 GenRandomName(opt->smbName);
412 /* username and domain for logon session is not necessarily the same as
413 username and domain passed into network provider. */
414 PSECURITY_LOGON_SESSION_DATA plsd;
415 char lsaUsername[MAX_USERNAME_LENGTH];
416 char lsaDomain[MAX_DOMAIN_LENGTH];
419 LsaGetLogonSessionData(lpLogonId, &plsd);
421 UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
422 UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
424 DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
426 if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
431 if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
438 opt->smbName = malloc(len);
440 StringCbCopy(opt->smbName, len, lsaDomain);
441 StringCbCat(opt->smbName, len, "\\");
442 StringCbCat(opt->smbName, len, lsaUsername);
444 strlwr(opt->smbName);
447 LsaFreeReturnBuffer(plsd);
450 DebugEvent("Looking up logon script");
452 /* First find out where the key is */
457 rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
458 if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
460 DebugEvent("Located logon script in hkDom");
463 rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
464 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
466 DebugEvent("Located logon script in hkDoms");
468 /* Note that the LogonScript in the NP key is only used if we are doing high security. */
469 else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
470 rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
471 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
473 DebugEvent("Located logon script in hkNp");
477 WCHAR *regscript = NULL;
478 WCHAR *regexscript = NULL;
479 WCHAR *regexuscript = NULL;
480 WCHAR *wuname = NULL;
485 StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
488 wuname = malloc(len * sizeof(WCHAR));
489 MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,len*sizeof(WCHAR));
491 DebugEvent("Username is set for [%S]", wuname);
493 /* dwSize still has the size of the required buffer in bytes. */
494 regscript = malloc(dwSize);
495 rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
496 if(rv != ERROR_SUCCESS) {/* what the ..? */
497 DebugEvent("Can't look up logon script [%d]",rv);
498 goto doneLogonScript;
501 DebugEvent("Found logon script [%S]", regscript);
503 if(dwType == REG_EXPAND_SZ) {
506 dwSize += MAX_PATH * sizeof(WCHAR); /* make room for environment expansion. */
507 regexscript = malloc(dwSize);
508 dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
510 regscript = regexscript;
512 if(dwReq > (dwSize / sizeof(WCHAR))) {
513 DebugEvent("Overflow while expanding environment strings.");
514 goto doneLogonScript;
518 DebugEvent("After expanding env strings [%S]", regscript);
520 if(wcsstr(regscript, L"%s")) {
521 dwSize += len * sizeof(WCHAR); /* make room for username expansion */
522 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
523 hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
525 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
526 hr = StringCbCopyW(regexuscript, dwSize, regscript);
529 DebugEvent("After expanding username [%S]", regexuscript);
532 opt->logonScript = regexuscript;
534 LocalFree(regexuscript);
537 if(wuname) free(wuname);
538 if(regscript) free(regscript);
539 if(regexscript) free(regexscript);
542 DebugEvent("Looking up TheseCells");
544 /* First find out where the key is */
549 rv = RegQueryValueEx(hkDom, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
550 if (rv == ERROR_SUCCESS && dwType == REG_MULTI_SZ) {
552 DebugEvent("Located TheseCells in hkDom");
554 rv = RegQueryValueEx(hkDoms, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
555 if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
557 DebugEvent("Located TheseCells in hkDoms");
559 rv = RegQueryValueEx(hkNp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
560 if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
562 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;
992 /* Make sure the AFS Libraries are initialized */
995 DebugEvent0("AFS_Logoff_Event - Start");
997 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
999 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1000 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1002 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1004 DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1009 /* We can't use pInfo->Domain for the domain since in the cross realm case
1010 * this is source domain and not the destination domain.
1012 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1013 WCHAR Domain[64]=L"";
1014 GetLocalShortDomain(Domain, sizeof(Domain));
1015 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1016 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1017 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1021 if (strlen(profileDir)) {
1022 DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1023 if (!IsPathInAfs(profileDir)) {
1024 if (code = ktc_ForgetAllTokens())
1025 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1027 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1029 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1032 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1036 LocalFree(tokenUser);
1038 DebugEvent0("AFS_Logoff_Event - End");
1041 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1044 TCHAR profileDir[1024] = TEXT("");
1046 PTOKEN_USER tokenUser = NULL;
1050 WCHAR szUserW[128] = L"";
1051 char szUserA[128] = "";
1052 char szClient[MAX_PATH];
1053 char szPath[MAX_PATH] = "";
1059 /* Make sure the AFS Libraries are initialized */
1062 DebugEvent0("AFS_Logon_Event - Start");
1064 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1066 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1067 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1069 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1071 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1076 /* We can't use pInfo->Domain for the domain since in the cross realm case
1077 * this is source domain and not the destination domain.
1079 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1080 WCHAR Domain[64]=L"";
1081 GetLocalShortDomain(Domain, sizeof(Domain));
1082 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1083 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1084 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1088 if (strlen(profileDir)) {
1089 DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1091 DebugEvent0("AFS_Logon_Event - Unable to load profile");
1094 dwSize = sizeof(szUserA);
1095 if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1096 StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1097 WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1102 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1103 StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1105 DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1107 memset (&nr, 0x00, sizeof(NETRESOURCE));
1108 nr.dwType=RESOURCETYPE_DISK;
1110 nr.lpRemoteName=szPath;
1111 res = WNetAddConnection2(&nr,NULL,szUserA,0);
1113 DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1114 szPath, szUserA,res);
1116 DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1118 DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1121 LocalFree(tokenUser);
1123 DebugEvent0("AFS_Logon_Event - End");