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];
45 if (!ISLOGONTRACE(TraceOption))
48 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
50 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
51 DeregisterEventSource(h);
55 void DebugEvent(char *b,...)
57 HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
60 if (!ISLOGONTRACE(TraceOption))
63 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
65 StringCbVPrintf(buf, MAXBUF_+1,b,marker);
68 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
69 DeregisterEventSource(h);
73 static HANDLE hInitMutex = NULL;
74 static BOOL bInit = FALSE;
76 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
80 case DLL_PROCESS_ATTACH:
81 /* Initialization Mutex */
82 hInitMutex = CreateMutex(NULL, FALSE, NULL);
85 case DLL_PROCESS_DETACH:
86 CloseHandle(hInitMutex);
89 case DLL_THREAD_ATTACH:
90 case DLL_THREAD_DETACH:
92 /* Everything else succeeds but does nothing. */
99 void AfsLogonInit(void)
101 if ( bInit == FALSE ) {
102 if ( WaitForSingleObject( hInitMutex, INFINITE ) == WAIT_OBJECT_0 ) {
103 if ( bInit == FALSE ) {
109 ReleaseMutex(hInitMutex);
114 CHAR *GenRandomName(CHAR *pbuf)
117 srand( (unsigned)time( NULL ) );
118 for (i=0;i<MAXRANDOMNAMELEN-1;i++)
119 pbuf[i]='a'+(rand() % 26);
120 pbuf[MAXRANDOMNAMELEN-1]=0;
124 BOOLEAN AFSWillAutoStart(void)
129 BOOLEAN result = FALSE;
130 LPQUERY_SERVICE_CONFIG pConfig = NULL;
134 /* Open services manager */
135 scm = OpenSCManager(NULL, NULL, GENERIC_READ);
136 if (!scm) return FALSE;
138 /* Open AFSD service */
139 svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
143 /* Query AFSD service config, first just to get buffer size */
144 /* Expected to fail, so don't test return value */
145 (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
146 status = GetLastError();
147 if (status != ERROR_INSUFFICIENT_BUFFER)
150 /* Allocate buffer */
151 pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
155 /* Query AFSD service config, this time for real */
156 flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
160 /* Is it autostart? */
161 if (pConfig->dwStartType < SERVICE_DEMAND_START)
167 CloseServiceHandle(svc);
169 CloseServiceHandle(scm);
174 DWORD MapAuthError(DWORD code)
177 /* Unfortunately, returning WN_NO_NETWORK results in the MPR abandoning
178 * logon scripts for all credential managers, although they will still
179 * receive logon notifications. Since we don't want this, we return
180 * WN_SUCCESS. This is highly undesirable, but we also don't want to
181 * break other network providers.
185 return WN_NO_NETWORK; */
186 default: return WN_SUCCESS;
190 DWORD APIENTRY NPGetCaps(DWORD index)
194 /* Don't have our own type; use somebody else's. */
195 return WNNC_NET_SUN_PC_NFS;
198 /* Say we are already started, even though we might wait after we receive NPLogonNotify */
207 NetUserGetProfilePath( LPCWSTR Domain, LPCWSTR UserName, char * profilePath,
208 DWORD profilePathLen )
211 LPWSTR ServerName = NULL;
212 LPUSER_INFO_3 p3 = NULL;
214 NetGetAnyDCName(NULL, Domain, (LPBYTE *)&ServerName);
215 /* if NetGetAnyDCName fails, ServerName == NULL
216 * NetUserGetInfo will obtain local user information
218 code = NetUserGetInfo(ServerName, UserName, 3, (LPBYTE *)&p3);
219 if (code == NERR_Success)
221 code = NERR_UserNotFound;
223 if (p3->usri3_profile) {
224 DWORD len = lstrlenW(p3->usri3_profile);
226 /* Convert From Unicode to ANSI (UTF-8 for future) */
227 len = len < profilePathLen ? len : profilePathLen - 1;
228 WideCharToMultiByte(CP_UTF8, 0, p3->usri3_profile, len, profilePath, len, NULL, NULL);
229 profilePath[len] = '\0';
233 NetApiBufferFree(p3);
237 NetApiBufferFree(ServerName);
241 BOOL IsServiceRunning (void)
243 SERVICE_STATUS Status;
245 memset (&Status, 0x00, sizeof(Status));
246 Status.dwCurrentState = SERVICE_STOPPED;
248 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
251 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
253 QueryServiceStatus (hService, &Status);
254 CloseServiceHandle (hService);
257 CloseServiceHandle (hManager);
259 DebugEvent("AFS AfsLogon - Test Service Running","Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
260 return (Status.dwCurrentState == SERVICE_RUNNING);
263 BOOL IsServiceStartPending (void)
265 SERVICE_STATUS Status;
267 memset (&Status, 0x00, sizeof(Status));
268 Status.dwCurrentState = SERVICE_STOPPED;
270 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
273 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
275 QueryServiceStatus (hService, &Status);
276 CloseServiceHandle (hService);
279 CloseServiceHandle (hManager);
281 DebugEvent("AFS AfsLogon - Test Service Start Pending","Return Code[%x] ?Start Pending[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_START_PENDING));
282 return (Status.dwCurrentState == SERVICE_START_PENDING);
285 /* LOOKUPKEYCHAIN: macro to look up the value in the list of keys in order until it's found
286 v:variable to receive value (reference type)
288 d:default, in case the value isn't on any of the keys
290 #define LOOKUPKEYCHAIN(v,t,d,n) \
292 rv = ~ERROR_SUCCESS; \
295 dwSize = sizeof(v); \
296 rv = RegQueryValueEx(hkDom, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
297 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDom with type [%d]", dwType); \
299 if(hkDoms && (rv != ERROR_SUCCESS || dwType != t)) { \
300 dwSize = sizeof(v); \
301 rv = RegQueryValueEx(hkDoms, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
302 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDoms with type [%d]", dwType); \
304 if(hkNp && (rv != ERROR_SUCCESS || dwType != t)) { \
305 dwSize = sizeof(v); \
306 rv = RegQueryValueEx(hkNp, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
307 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkNp with type [%d]", dwType); \
309 if(rv != ERROR_SUCCESS || dwType != t) { \
311 DebugEvent(#v " being set to default"); \
315 /* Get domain specific configuration info. We are returning void because if anything goes wrong
316 we just return defaults.
319 GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
320 HKEY hkParm = NULL; /* Service parameter */
321 HKEY hkNp = NULL; /* network provider key */
322 HKEY hkDoms = NULL; /* domains key */
323 HKEY hkDom = NULL; /* DOMAINS/domain key */
329 char computerName[MAX_COMPUTERNAME_LENGTH + 1];
332 memset(opt, 0, sizeof(LogonOptions_t));
334 DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
335 /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
336 opt->flags = LOGON_FLAG_REMOTE;
338 dwSize = MAX_COMPUTERNAME_LENGTH;
339 if(GetComputerName(computerName, &dwSize)) {
340 if(!stricmp(computerName, domain)) {
341 effDomain = "LOCALHOST";
342 opt->flags = LOGON_FLAG_LOCAL;
350 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, KEY_READ, &hkParm );
351 if(rv != ERROR_SUCCESS) {
353 DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
356 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PROVIDER_SUBKEY, 0, KEY_READ, &hkNp );
357 if(rv != ERROR_SUCCESS) {
359 DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
363 rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
364 if( rv != ERROR_SUCCESS ) {
366 DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
370 if(hkDoms && effDomain) {
371 rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
372 if( rv != ERROR_SUCCESS ) {
374 DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
375 /* If none of the domains match, we shouldn't use the domain key either */
380 DebugEvent("Not opening domain key for [%s]", effDomain);
382 /* Each individual can either be specified on the domain key, the domains key or in the
383 net provider key. They fail over in that order. If none is found, we just use the
387 LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
389 /* FailLoginsSilently */
390 dwSize = sizeof(dwDummy);
391 rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
392 if (rv != ERROR_SUCCESS)
393 LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
394 opt->failSilently = !!dwDummy;
397 LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
400 LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
402 opt->logonScript = NULL;
405 if(!ISLOGONINTEGRATED(opt->LogonOption)) {
406 goto cleanup; /* no need to lookup the logon script */
409 /* come up with SMB username */
410 if(ISHIGHSECURITY(opt->LogonOption)) {
411 opt->smbName = malloc( MAXRANDOMNAMELEN );
412 GenRandomName(opt->smbName);
414 /* username and domain for logon session is not necessarily the same as
415 username and domain passed into network provider. */
416 PSECURITY_LOGON_SESSION_DATA plsd;
417 char lsaUsername[MAX_USERNAME_LENGTH];
418 char lsaDomain[MAX_DOMAIN_LENGTH];
421 LsaGetLogonSessionData(lpLogonId, &plsd);
423 UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
424 UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
426 DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
428 if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
433 if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
440 opt->smbName = malloc(len);
442 StringCbCopy(opt->smbName, len, lsaDomain);
443 StringCbCat(opt->smbName, len, "\\");
444 StringCbCat(opt->smbName, len, lsaUsername);
446 strlwr(opt->smbName);
449 LsaFreeReturnBuffer(plsd);
452 DebugEvent("Looking up logon script");
454 /* First find out where the key is */
459 rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
460 if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
462 DebugEvent("Located logon script in hkDom");
465 rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
466 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
468 DebugEvent("Located logon script in hkDoms");
470 /* Note that the LogonScript in the NP key is only used if we are doing high security. */
471 else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
472 rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
473 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
475 DebugEvent("Located logon script in hkNp");
479 WCHAR *regscript = NULL;
480 WCHAR *regexscript = NULL;
481 WCHAR *regexuscript = NULL;
482 WCHAR *wuname = NULL;
487 StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
490 wuname = malloc(len * sizeof(WCHAR));
491 MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,len*sizeof(WCHAR));
493 DebugEvent("Username is set for [%S]", wuname);
495 /* dwSize still has the size of the required buffer in bytes. */
496 regscript = malloc(dwSize);
497 rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
498 if(rv != ERROR_SUCCESS) {/* what the ..? */
499 DebugEvent("Can't look up logon script [%d]",rv);
500 goto doneLogonScript;
503 DebugEvent("Found logon script [%S]", regscript);
505 if(dwType == REG_EXPAND_SZ) {
508 dwSize += MAX_PATH * sizeof(WCHAR); /* make room for environment expansion. */
509 regexscript = malloc(dwSize);
510 dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
512 regscript = regexscript;
514 if(dwReq > (dwSize / sizeof(WCHAR))) {
515 DebugEvent("Overflow while expanding environment strings.");
516 goto doneLogonScript;
520 DebugEvent("After expanding env strings [%S]", regscript);
522 if(wcsstr(regscript, L"%s")) {
523 dwSize += len * sizeof(WCHAR); /* make room for username expansion */
524 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
525 hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
527 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
528 hr = StringCbCopyW(regexuscript, dwSize, regscript);
531 DebugEvent("After expanding username [%S]", regexuscript);
534 opt->logonScript = regexuscript;
536 LocalFree(regexuscript);
539 if(wuname) free(wuname);
540 if(regscript) free(regscript);
541 if(regexscript) free(regexscript);
544 DebugEvent("Looking up TheseCells");
546 /* First find out where the key is */
551 rv = RegQueryValueEx(hkDom, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
552 if (rv == ERROR_SUCCESS && dwType == REG_MULTI_SZ) {
554 DebugEvent("Located TheseCells in hkDom");
556 rv = RegQueryValueEx(hkDoms, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
557 if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
559 DebugEvent("Located TheseCells in hkDoms");
561 rv = RegQueryValueEx(hkNp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
562 if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
564 DebugEvent("Located TheseCells in hkNp");
570 /* dwSize still has the size of the required buffer in bytes. */
571 thesecells = malloc(dwSize);
572 rv = RegQueryValueEx(hkTemp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, (LPBYTE) thesecells, &dwSize);
573 if(rv != ERROR_SUCCESS) {/* what the ..? */
574 DebugEvent("Can't look up TheseCells [%d]",rv);
578 DebugEvent("Found TheseCells [%s]", thesecells);
579 opt->theseCells = thesecells;
585 if(hkNp) RegCloseKey(hkNp);
586 if(hkDom) RegCloseKey(hkDom);
587 if(hkDoms) RegCloseKey(hkDoms);
588 if(hkParm) RegCloseKey(hkParm);
591 #undef LOOKUPKEYCHAIN
593 /* Try to find out which cell the given path is in. We must retain
594 the contents of *cell in case of failure. *cell is assumed to be
595 at least cellLen chars */
596 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
597 struct ViceIoctl blob;
598 char tcell[MAX_PATH];
602 blob.out_size = MAX_PATH;
605 code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
608 strncpy(cell, tcell, cellLen);
609 cell[cellLen - 1] = '\0';
617 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
621 GetCPInfo(CP_ACP, &CodePageInfo);
623 if (CodePageInfo.MaxCharSize > 1)
624 // Only supporting non-Unicode strings
627 if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
629 // Looks like unicode, better translate it
630 // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
631 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
632 lpszOutputString, nOutStringLen-1, NULL, NULL);
633 lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
637 lpszOutputString[0] = '\0';
639 } // UnicodeStringToANSI
641 DWORD APIENTRY NPLogonNotify(
643 LPCWSTR lpAuthentInfoType,
644 LPVOID lpAuthentInfo,
645 LPCWSTR lpPreviousAuthentInfoType,
646 LPVOID lpPreviousAuthentInfo,
647 LPWSTR lpStationName,
648 LPVOID StationHandle,
649 LPWSTR *lpLogonScript)
651 char uname[MAX_USERNAME_LENGTH]="";
652 char password[MAX_PASSWORD_LENGTH]="";
653 char logonDomain[MAX_DOMAIN_LENGTH]="";
654 char cell[256]="<non-integrated logon>";
655 char homePath[MAX_PATH]="";
656 char szLogonId[128] = "";
658 MSV1_0_INTERACTIVE_LOGON *IL;
668 DWORD LSPtype, LSPsize;
671 HWND hwndOwner = (HWND)StationHandle;
673 BOOLEAN afsWillAutoStart;
675 BOOLEAN lowercased_name = TRUE;
677 LogonOptions_t opt; /* domain specific logon options */
681 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
682 0, KEY_QUERY_VALUE, &NPKey);
683 LSPsize=sizeof(TraceOption);
684 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
685 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
689 DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart);
691 /* Make sure the AFS Libraries are initialized */
694 /* Initialize Logon Script to none */
697 /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for
700 if ( wcscmp(lpAuthentInfoType,L"MSV1_0:Interactive") &&
701 wcscmp(lpAuthentInfoType,L"Kerberos:Interactive") )
703 DebugEvent("Unsupported Authentication Info Type: %S",
708 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
710 /* Are we interactive? */
711 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
713 /* Convert from Unicode to ANSI */
715 /*TODO: Use SecureZeroMemory to erase passwords */
716 UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
717 UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
718 UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
720 /* Make sure AD-DOMANS sent from login that is sent to us is striped */
721 ctemp = strchr(uname, '@');
722 if (ctemp) *ctemp = 0;
724 /* is the name all lowercase? */
725 for ( ctemp = uname; *ctemp ; ctemp++) {
726 if ( !islower(*ctemp) ) {
727 lowercased_name = FALSE;
736 GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
737 retryInterval = opt.retryInterval;
738 sleepInterval = opt.sleepInterval;
739 *lpLogonScript = opt.logonScript;
741 if (retryInterval < sleepInterval)
742 sleepInterval = retryInterval;
744 DebugEvent("Got logon script: %S",opt.logonScript);
746 afsWillAutoStart = AFSWillAutoStart();
748 DebugEvent("LogonOption[%x], Service AutoStart[%d]",
749 opt.LogonOption,afsWillAutoStart);
751 /* Check for zero length password if integrated logon*/
752 if ( ISLOGONINTEGRATED(opt.LogonOption) ) {
753 if ( password[0] == 0 ) {
754 DebugEvent("Password is the empty string");
756 reason = "zero length password is illegal";
760 /* Get cell name if doing integrated logon.
761 We might overwrite this if we are logging into an AD realm and we find out that
762 the user's home dir is in some other cell. */
763 DebugEvent("About to call cm_GetRootCellName(%s)",cell);
764 code = cm_GetRootCellName(cell);
766 DebugEvent("Unable to obtain Root Cell");
768 reason = "unknown cell";
771 DebugEvent("Cell is %s",cell);
774 /* We get the user's home directory path, if applicable, though we can't lookup the
775 cell right away because the client service may not have started yet. This call
776 also sets the AD_REALM flag in opt.flags if applicable. */
777 if (ISREMOTE(opt.flags)) {
778 DebugEvent("Is Remote");
779 GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
783 /* loop until AFS is started. */
784 while (IsServiceRunning() || IsServiceStartPending()) {
785 DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
786 opt.LogonOption,afsWillAutoStart);
788 if (ISADREALM(opt.flags)) {
789 code = GetFileCellName(homePath,cell,256);
791 DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
793 /* Don't bail out if GetFileCellName failed.
794 * The home dir may not be in AFS after all.
799 /* if Integrated Logon */
800 if (ISLOGONINTEGRATED(opt.LogonOption))
802 if ( KFW_is_available() ) {
803 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
804 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",uname,opt.smbName,cell,code);
805 if (code == 0 && opt.theseCells) {
806 char * principal, *p;
808 principal = (char *)malloc(strlen(uname) + strlen(cell) + 2);
810 strcpy(principal, uname);
811 p = principal + strlen(uname);
820 code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
821 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
822 principal,opt.smbName,p,code2);
830 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
831 uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
833 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s]",
836 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
837 for ( ctemp = uname; *ctemp ; ctemp++) {
838 *ctemp = tolower(*ctemp);
840 lowercased_name = TRUE;
844 /* is service started yet?*/
846 /* If we've failed because the client isn't running yet and the
847 * client is set to autostart (and therefore it makes sense for
848 * us to wait for it to start) then sleep a while and try again.
849 * If the error was something else, then give up. */
850 if (code != KTC_NOCM && code != KTC_NOCMRPC)
854 /*JUST check to see if its running*/
855 if (IsServiceRunning())
857 if (!IsServiceStartPending()) {
859 reason = "AFS Service start failed";
864 /* If the retry interval has expired and we still aren't
865 * logged in, then just give up if we are not in interactive
866 * mode or the failSilently flag is set, otherwise let the
867 * user know we failed and give them a chance to try again. */
868 if (retryInterval <= 0) {
869 reason = "AFS not running";
870 if (!interactive || opt.failSilently)
872 flag = MessageBox(hwndOwner,
873 "AFS is still starting. Retry?",
875 MB_ICONQUESTION | MB_RETRYCANCEL);
876 if (flag == IDCANCEL)
879 /* Wait just a little while and try again */
880 retryInterval = opt.retryInterval;
884 Sleep(sleepInterval * 1000);
885 retryInterval -= sleepInterval;
888 DebugEvent("while loop exited");
889 /* remove any kerberos 5 tickets currently held by the SYSTEM account
892 if ( KFW_is_available() ) {
893 sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
894 KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
896 KFW_AFS_destroy_tickets_for_principal(uname);
904 StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
906 if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
907 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
909 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
911 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
913 DeregisterEventSource(h);
915 code = MapAuthError(code);
918 if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
921 LocalFree(*lpLogonScript);
922 *lpLogonScript = NULL;
923 if (!afsWillAutoStart) // its not running, so if not autostart or integrated logon then just skip
928 if (opt.theseCells) free(opt.theseCells);
929 if (opt.smbName) free(opt.smbName);
931 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
935 DWORD APIENTRY NPPasswordChangeNotify(
936 LPCWSTR lpAuthentInfoType,
937 LPVOID lpAuthentInfo,
938 LPCWSTR lpPreviousAuthentInfoType,
939 LPVOID lpPreviousAuthentInfo,
940 LPWSTR lpStationName,
941 LPVOID StationHandle,
944 /* Make sure the AFS Libraries are initialized */
947 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
953 #include <afs/vice.h>
954 #include <afs/fs_utils.h>
956 BOOL IsPathInAfs(const CHAR *strPath)
959 struct ViceIoctl blob;
963 blob.out_size = 2048;
966 code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
973 typedef struct _WLX_NOTIFICATION_INFO {
981 PFNMSGECALLBACK pStatusCallback;
982 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
985 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
987 DWORD LSPtype, LSPsize;
990 /* Make sure the AFS Libraries are initialized */
993 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
994 0, KEY_QUERY_VALUE, &NPKey);
995 LSPsize=sizeof(TraceOption);
996 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
997 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
1000 DebugEvent0("AFS_Startup_Event");
1003 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
1006 TCHAR profileDir[1024] = TEXT("");
1008 PTOKEN_USER tokenUser = NULL;
1010 DWORD LSPtype, LSPsize;
1012 DWORD LogoffPreserveTokens = 0;
1014 /* Make sure the AFS Libraries are initialized */
1017 DebugEvent0("AFS_Logoff_Event - Start");
1019 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1020 0, KEY_QUERY_VALUE, &NPKey);
1021 LSPsize=sizeof(LogoffPreserveTokens);
1022 RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
1023 &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
1024 RegCloseKey (NPKey);
1026 if (LogoffPreserveTokens) {
1027 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1029 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1030 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1032 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1034 DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1039 /* We can't use pInfo->Domain for the domain since in the cross realm case
1040 * this is source domain and not the destination domain.
1042 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1043 WCHAR Domain[64]=L"";
1044 GetLocalShortDomain(Domain, sizeof(Domain));
1045 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1046 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1047 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1051 if (strlen(profileDir)) {
1052 DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1053 if (!IsPathInAfs(profileDir)) {
1054 if (code = ktc_ForgetAllTokens())
1055 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1057 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1059 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1062 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1066 LocalFree(tokenUser);
1069 DebugEvent0("AFS_Logoff_Event - End");
1072 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1074 TCHAR profileDir[1024] = TEXT("");
1076 PTOKEN_USER tokenUser = NULL;
1078 WCHAR szUserW[128] = L"";
1079 char szUserA[128] = "";
1080 char szClient[MAX_PATH];
1081 char szPath[MAX_PATH] = "";
1086 /* Make sure the AFS Libraries are initialized */
1089 DebugEvent0("AFS_Logon_Event - Start");
1091 DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1093 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1095 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1096 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1098 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1100 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1105 /* We can't use pInfo->Domain for the domain since in the cross realm case
1106 * this is source domain and not the destination domain.
1108 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1109 WCHAR Domain[64]=L"";
1110 GetLocalShortDomain(Domain, sizeof(Domain));
1111 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1112 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1113 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1117 if (strlen(profileDir)) {
1118 DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1120 DebugEvent0("AFS_Logon_Event - Unable to load profile");
1123 dwSize = sizeof(szUserA);
1124 if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1125 StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1126 WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1131 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1132 StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1134 DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1136 memset (&nr, 0x00, sizeof(NETRESOURCE));
1137 nr.dwType=RESOURCETYPE_DISK;
1139 nr.lpRemoteName=szPath;
1140 res = WNetAddConnection2(&nr,NULL,szUserA,0);
1142 DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1143 szPath, szUserA,res);
1145 DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1147 DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1150 LocalFree(tokenUser);
1152 DebugEvent0("AFS_Logon_Event - End");
1156 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1158 NTSTATUS Status = 0;
1160 TOKEN_STATISTICS Stats;
1166 *ppSessionData = NULL;
1169 Success = OpenProcessToken( HANDLE GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
1174 Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1176 CloseHandle( TokenHandle );
1181 Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1182 if ( FAILED(Status) || !ppSessionData )
1188 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1192 WCHAR szUserW[128] = L"";
1193 char szUserA[128] = "";
1194 char szClient[MAX_PATH];
1195 char szPath[MAX_PATH] = "";
1196 char szLogonId[128] = "";
1206 char commandline[512];
1207 STARTUPINFO startupinfo;
1208 PROCESS_INFORMATION procinfo;
1210 LUID LogonId = {0, 0};
1211 PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1213 HKEY hKey1 = NULL, hKey2 = NULL;
1215 /* Make sure the KFW Libraries are initialized */
1218 DebugEvent0("KFW_Logon_Event - Start");
1220 GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1222 if ( pLogonSessionData ) {
1223 LogonId = pLogonSessionData->LogonId;
1224 DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1226 sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1227 LsaFreeReturnBuffer( pLogonSessionData );
1229 DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1233 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1234 if ( count > sizeof(filename) || count == 0 ) {
1235 GetWindowsDirectory(filename, sizeof(filename));
1238 if ( strlen(filename) + strlen(szLogonId) + 2 <= sizeof(filename) ) {
1239 strcat(filename, "\\");
1240 strcat(filename, szLogonId);
1242 sprintf(commandline, "afscpcc.exe \"%s\"", filename);
1244 GetStartupInfo(&startupinfo);
1245 if (CreateProcessAsUser( pInfo->hToken,
1251 CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1257 WaitForSingleObject(procinfo.hProcess, 30000);
1259 CloseHandle(procinfo.hThread);
1260 CloseHandle(procinfo.hProcess);
1264 DeleteFile(filename);
1266 DebugEvent0("KFW_Logon_Event - End");