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);
413 } else if (lpLogonId) {
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);
453 DebugEvent("No LUID given. Constructing username using [%s] and [%s]",
456 len = strlen(username) + strlen(domain) + 2;
458 opt->smbName = malloc(len);
460 StringCbCopy(opt->smbName, len, username);
461 StringCbCat(opt->smbName, len, "\\");
462 StringCbCat(opt->smbName, len, domain);
464 strlwr(opt->smbName);
467 DebugEvent("Looking up logon script");
469 /* First find out where the key is */
474 rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
475 if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
477 DebugEvent("Located logon script in hkDom");
480 rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
481 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
483 DebugEvent("Located logon script in hkDoms");
485 /* Note that the LogonScript in the NP key is only used if we are doing high security. */
486 else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
487 rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
488 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
490 DebugEvent("Located logon script in hkNp");
494 WCHAR *regscript = NULL;
495 WCHAR *regexscript = NULL;
496 WCHAR *regexuscript = NULL;
497 WCHAR *wuname = NULL;
502 StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
505 wuname = malloc(len * sizeof(WCHAR));
506 MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,(int)(len*sizeof(WCHAR)));
508 DebugEvent("Username is set for [%S]", wuname);
510 /* dwSize still has the size of the required buffer in bytes. */
511 regscript = malloc(dwSize);
512 rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
513 if(rv != ERROR_SUCCESS) {/* what the ..? */
514 DebugEvent("Can't look up logon script [%d]",rv);
515 goto doneLogonScript;
518 DebugEvent("Found logon script [%S]", regscript);
520 if(dwType == REG_EXPAND_SZ) {
523 dwSize += MAX_PATH * sizeof(WCHAR); /* make room for environment expansion. */
524 regexscript = malloc(dwSize);
525 dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
527 regscript = regexscript;
529 if(dwReq > (dwSize / sizeof(WCHAR))) {
530 DebugEvent("Overflow while expanding environment strings.");
531 goto doneLogonScript;
535 DebugEvent("After expanding env strings [%S]", regscript);
537 if(wcsstr(regscript, L"%s")) {
538 dwSize += (DWORD)(len * sizeof(WCHAR)); /* make room for username expansion */
539 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
540 hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
542 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
543 hr = StringCbCopyW(regexuscript, dwSize, regscript);
546 DebugEvent("After expanding username [%S]", regexuscript);
549 opt->logonScript = regexuscript;
551 LocalFree(regexuscript);
554 if(wuname) free(wuname);
555 if(regscript) free(regscript);
556 if(regexscript) free(regexscript);
559 DebugEvent("Looking up TheseCells");
561 /* First find out where the key is */
566 rv = RegQueryValueEx(hkDom, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
567 if (rv == ERROR_SUCCESS && dwType == REG_MULTI_SZ) {
569 DebugEvent("Located TheseCells in hkDom");
571 rv = RegQueryValueEx(hkDoms, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
572 if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
574 DebugEvent("Located TheseCells in hkDoms");
576 rv = RegQueryValueEx(hkNp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
577 if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
579 DebugEvent("Located TheseCells in hkNp");
585 /* dwSize still has the size of the required buffer in bytes. */
586 thesecells = malloc(dwSize);
587 rv = RegQueryValueEx(hkTemp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, (LPBYTE) thesecells, &dwSize);
588 if(rv != ERROR_SUCCESS) {/* what the ..? */
589 DebugEvent("Can't look up TheseCells [%d]",rv);
593 DebugEvent("Found TheseCells [%s]", thesecells);
594 opt->theseCells = thesecells;
601 if(hkNp) RegCloseKey(hkNp);
602 if(hkDom) RegCloseKey(hkDom);
603 if(hkDoms) RegCloseKey(hkDoms);
604 if(hkParm) RegCloseKey(hkParm);
607 #undef LOOKUPKEYCHAIN
609 /* Try to find out which cell the given path is in. We must retain
610 the contents of *cell in case of failure. *cell is assumed to be
611 at least cellLen chars */
612 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
613 struct ViceIoctl blob;
614 char tcell[MAX_PATH];
618 blob.out_size = MAX_PATH;
621 code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
624 strncpy(cell, tcell, cellLen);
625 cell[cellLen - 1] = '\0';
633 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
637 GetCPInfo(CP_ACP, &CodePageInfo);
639 if (CodePageInfo.MaxCharSize > 1)
640 // Only supporting non-Unicode strings
643 if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
645 // Looks like unicode, better translate it
646 // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
647 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
648 lpszOutputString, nOutStringLen-1, NULL, NULL);
649 lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
653 lpszOutputString[0] = '\0';
655 } // UnicodeStringToANSI
657 DWORD APIENTRY NPLogonNotify(
659 LPCWSTR lpAuthentInfoType,
660 LPVOID lpAuthentInfo,
661 LPCWSTR lpPreviousAuthentInfoType,
662 LPVOID lpPreviousAuthentInfo,
663 LPWSTR lpStationName,
664 LPVOID StationHandle,
665 LPWSTR *lpLogonScript)
667 char uname[MAX_USERNAME_LENGTH]="";
668 char password[MAX_PASSWORD_LENGTH]="";
669 char logonDomain[MAX_DOMAIN_LENGTH]="";
670 char cell[256]="<non-integrated logon>";
671 char homePath[MAX_PATH]="";
672 char szLogonId[128] = "";
674 MSV1_0_INTERACTIVE_LOGON *IL;
676 DWORD code = 0, code2;
684 DWORD LSPtype, LSPsize;
687 HWND hwndOwner = (HWND)StationHandle;
689 BOOLEAN afsWillAutoStart;
691 BOOLEAN lowercased_name = TRUE;
693 LogonOptions_t opt; /* domain specific logon options */
697 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
698 0, KEY_QUERY_VALUE, &NPKey);
699 LSPsize=sizeof(TraceOption);
700 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
701 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
705 DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart);
707 /* Make sure the AFS Libraries are initialized */
710 /* Initialize Logon Script to none */
713 /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for
716 if ( wcscmp(lpAuthentInfoType,L"MSV1_0:Interactive") &&
717 wcscmp(lpAuthentInfoType,L"Kerberos:Interactive") )
719 DebugEvent("Unsupported Authentication Info Type: %S",
724 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
726 /* Are we interactive? */
727 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
729 /* Convert from Unicode to ANSI */
731 /*TODO: Use SecureZeroMemory to erase passwords */
732 UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
733 UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
734 UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
736 /* Make sure AD-DOMANS sent from login that is sent to us is striped */
737 ctemp = strchr(uname, '@');
738 if (ctemp) *ctemp = 0;
740 /* is the name all lowercase? */
741 for ( ctemp = uname; *ctemp ; ctemp++) {
742 if ( !islower(*ctemp) ) {
743 lowercased_name = FALSE;
752 GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
753 retryInterval = opt.retryInterval;
754 sleepInterval = opt.sleepInterval;
755 *lpLogonScript = opt.logonScript;
757 if (retryInterval < sleepInterval)
758 sleepInterval = retryInterval;
760 DebugEvent("Got logon script: %S",opt.logonScript);
762 afsWillAutoStart = AFSWillAutoStart();
764 DebugEvent("LogonOption[%x], Service AutoStart[%d]",
765 opt.LogonOption,afsWillAutoStart);
767 /* Check for zero length password if integrated logon*/
768 if ( ISLOGONINTEGRATED(opt.LogonOption) ) {
769 if ( password[0] == 0 ) {
770 DebugEvent("Password is the empty string");
772 reason = "zero length password is illegal";
776 /* Get cell name if doing integrated logon.
777 We might overwrite this if we are logging into an AD realm and we find out that
778 the user's home dir is in some other cell. */
779 DebugEvent("About to call cm_GetRootCellName(%s)",cell);
780 code = cm_GetRootCellName(cell);
782 DebugEvent("Unable to obtain Root Cell");
784 reason = "unknown cell";
787 DebugEvent("Cell is %s",cell);
790 /* We get the user's home directory path, if applicable, though we can't lookup the
791 cell right away because the client service may not have started yet. This call
792 also sets the AD_REALM flag in opt.flags if applicable. */
793 if (ISREMOTE(opt.flags)) {
794 DebugEvent("Is Remote");
795 GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
799 /* loop until AFS is started. */
800 if (afsWillAutoStart) {
801 while (IsServiceRunning() || IsServiceStartPending()) {
802 DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
803 opt.LogonOption,afsWillAutoStart);
805 if (ISADREALM(opt.flags)) {
806 code = GetFileCellName(homePath,cell,256);
808 DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
810 /* Don't bail out if GetFileCellName failed.
811 * The home dir may not be in AFS after all.
816 /* if Integrated Logon */
817 if (ISLOGONINTEGRATED(opt.LogonOption))
819 if ( KFW_is_available() ) {
820 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
821 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
822 uname,opt.smbName,cell,code);
823 if (code == 0 && opt.theseCells) {
824 char * principal, *p;
827 StringCchLength(cell, MAX_DOMAIN_LENGTH, &tlen);
829 StringCchLength(uname, MAX_USERNAME_LENGTH, &tlen);
832 /* tlen is now the length of uname in characters */
833 principal = (char *)malloc(len * sizeof(char));
835 StringCchCopy(principal, len, uname);
836 p = principal + tlen;
838 StringCchCopy(p, len - tlen - 1, cell);
845 code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
846 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
847 principal,opt.smbName,p,code2);
854 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
855 uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
857 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2 Code[%x] uname[%s] smbname=[%s] Cell[%s] PwExp=[%d] Reason=[%s]",
858 code,uname,opt.smbName,cell,pw_exp,reason?reason:"");
860 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
861 for ( ctemp = uname; *ctemp ; ctemp++) {
862 *ctemp = tolower(*ctemp);
864 lowercased_name = TRUE;
868 /* is service started yet?*/
870 /* If we've failed because the client isn't running yet and the
871 * client is set to autostart (and therefore it makes sense for
872 * us to wait for it to start) then sleep a while and try again.
873 * If the error was something else, then give up. */
874 if (code != KTC_NOCM && code != KTC_NOCMRPC)
878 /*JUST check to see if its running*/
879 if (IsServiceRunning())
881 if (!IsServiceStartPending()) {
883 reason = "AFS Service start failed";
888 /* If the retry interval has expired and we still aren't
889 * logged in, then just give up if we are not in interactive
890 * mode or the failSilently flag is set, otherwise let the
891 * user know we failed and give them a chance to try again. */
892 if (retryInterval <= 0) {
893 reason = "AFS not running";
894 if (!interactive || opt.failSilently)
896 flag = MessageBox(hwndOwner,
897 "AFS is still starting. Retry?",
899 MB_ICONQUESTION | MB_RETRYCANCEL);
900 if (flag == IDCANCEL)
903 /* Wait just a little while and try again */
904 retryInterval = opt.retryInterval;
908 Sleep(sleepInterval * 1000);
909 retryInterval -= sleepInterval;
912 DebugEvent("while loop exited");
913 /* remove any kerberos 5 tickets currently held by the SYSTEM account
916 if ( KFW_is_available() ) {
917 sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
918 KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
920 KFW_AFS_destroy_tickets_for_principal(uname);
928 StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
930 if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
931 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
933 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
935 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
937 DeregisterEventSource(h);
939 code = MapAuthError(code);
942 if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
945 LocalFree(*lpLogonScript);
946 *lpLogonScript = NULL;
947 if (!afsWillAutoStart) // its not running, so if not autostart or integrated logon then just skip
952 if (opt.theseCells) free(opt.theseCells);
953 if (opt.smbName) free(opt.smbName);
955 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
959 DWORD APIENTRY NPPasswordChangeNotify(
960 LPCWSTR lpAuthentInfoType,
961 LPVOID lpAuthentInfo,
962 LPCWSTR lpPreviousAuthentInfoType,
963 LPVOID lpPreviousAuthentInfo,
964 LPWSTR lpStationName,
965 LPVOID StationHandle,
968 /* Make sure the AFS Libraries are initialized */
971 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
977 #include <afs/vice.h>
978 #include <afs/fs_utils.h>
980 BOOL IsPathInAfs(const CHAR *strPath)
983 struct ViceIoctl blob;
987 blob.out_size = 2048;
990 code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
997 typedef struct _WLX_NOTIFICATION_INFO {
1002 PWSTR WindowStation;
1005 PFNMSGECALLBACK pStatusCallback;
1006 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
1009 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
1011 DWORD LSPtype, LSPsize;
1014 /* Make sure the AFS Libraries are initialized */
1017 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1018 0, KEY_QUERY_VALUE, &NPKey);
1019 LSPsize=sizeof(TraceOption);
1020 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
1021 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
1023 RegCloseKey (NPKey);
1024 DebugEvent0("AFS_Startup_Event");
1027 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
1030 TCHAR profileDir[1024] = TEXT("");
1032 PTOKEN_USER tokenUser = NULL;
1034 DWORD LSPtype, LSPsize;
1036 DWORD LogoffPreserveTokens = 0;
1039 /* Make sure the AFS Libraries are initialized */
1042 DebugEvent0("AFS_Logoff_Event - Start");
1044 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1045 0, KEY_QUERY_VALUE, &NPKey);
1046 LSPsize=sizeof(LogoffPreserveTokens);
1047 RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
1048 &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
1049 RegCloseKey (NPKey);
1051 if (!LogoffPreserveTokens) {
1052 memset(&opt, 0, sizeof(LogonOptions_t));
1054 if (pInfo->UserName && pInfo->Domain) {
1055 char username[MAX_USERNAME_LENGTH] = "";
1056 char domain[MAX_DOMAIN_LENGTH] = "";
1059 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1060 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1061 username, sizeof(username), NULL, NULL);
1063 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1064 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1065 domain, sizeof(domain), NULL, NULL);
1067 GetDomainLogonOptions(NULL, username, domain, &opt);
1070 if (ISREMOTE(opt.flags)) {
1071 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1073 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1074 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1076 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1078 DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1083 /* We can't use pInfo->Domain for the domain since in the cross realm case
1084 * this is source domain and not the destination domain.
1086 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1087 WCHAR Domain[64]=L"";
1088 GetLocalShortDomain(Domain, sizeof(Domain));
1089 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1090 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1091 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1095 if (strlen(profileDir)) {
1096 DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1097 if (!IsPathInAfs(profileDir)) {
1098 if (code = ktc_ForgetAllTokens())
1099 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1101 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1103 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1106 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1110 LocalFree(tokenUser);
1112 DebugEvent0("AFS_Logoff_Event - Local Logon");
1113 if (code = ktc_ForgetAllTokens())
1114 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1116 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1119 DebugEvent0("AFS_Logoff_Event - Preserving Tokens");
1122 DebugEvent0("AFS_Logoff_Event - End");
1125 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1127 TCHAR profileDir[1024] = TEXT("");
1129 PTOKEN_USER tokenUser = NULL;
1131 WCHAR szUserW[128] = L"";
1132 char szUserA[128] = "";
1133 char szClient[MAX_PATH];
1134 char szPath[MAX_PATH] = "";
1140 /* Make sure the AFS Libraries are initialized */
1143 DebugEvent0("AFS_Logon_Event - Start");
1145 DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1147 memset(&opt, 0, sizeof(LogonOptions_t));
1149 if (pInfo->UserName && pInfo->Domain) {
1150 char username[MAX_USERNAME_LENGTH] = "";
1151 char domain[MAX_DOMAIN_LENGTH] = "";
1154 DebugEvent0("AFS_Logon_Event - pInfo UserName and Domain");
1156 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1157 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1158 username, sizeof(username), NULL, NULL);
1160 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1161 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1162 domain, sizeof(domain), NULL, NULL);
1164 DebugEvent0("AFS_Logon_Event - Calling GetDomainLogonOptions");
1165 GetDomainLogonOptions(NULL, username, domain, &opt);
1167 if (!pInfo->UserName)
1168 DebugEvent0("AFS_Logon_Event - No pInfo->UserName");
1170 DebugEvent0("AFS_Logon_Event - No pInfo->Domain");
1173 DebugEvent("AFS_Logon_Event - opt.LogonOption = %lX opt.flags = %lX",
1174 opt.LogonOption, opt.flags);
1176 if (!ISLOGONINTEGRATED(opt.LogonOption) || !ISREMOTE(opt.flags)) {
1177 DebugEvent0("AFS_Logon_Event - Logon is not integrated or not remote");
1178 goto done_logon_event;
1181 DebugEvent0("AFS_Logon_Event - Calling GetTokenInformation");
1183 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1185 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1186 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1188 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1190 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1195 /* We can't use pInfo->Domain for the domain since in the cross realm case
1196 * this is source domain and not the destination domain.
1198 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1199 WCHAR Domain[64]=L"";
1200 GetLocalShortDomain(Domain, sizeof(Domain));
1201 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1202 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1203 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1207 if (strlen(profileDir)) {
1208 DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1210 DebugEvent0("AFS_Logon_Event - Unable to load profile");
1214 dwSize = sizeof(szUserA);
1215 if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1216 StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1217 WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1222 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1223 StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1225 DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1227 memset (&nr, 0x00, sizeof(NETRESOURCE));
1228 nr.dwType=RESOURCETYPE_DISK;
1230 nr.lpRemoteName=szPath;
1231 res = WNetAddConnection2(&nr,NULL,szUserA,0);
1233 DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1234 szPath, szUserA,res);
1236 DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1238 DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1241 LocalFree(tokenUser);
1243 DebugEvent0("AFS_Logon_Event - End");
1247 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1249 NTSTATUS Status = 0;
1250 TOKEN_STATISTICS Stats;
1256 *ppSessionData = NULL;
1258 Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1262 Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1263 if ( FAILED(Status) || !ppSessionData )
1269 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1271 WCHAR szUserW[128] = L"";
1272 char szUserA[128] = "";
1273 char szPath[MAX_PATH] = "";
1274 char szLogonId[128] = "";
1277 char commandline[512];
1278 STARTUPINFO startupinfo;
1279 PROCESS_INFORMATION procinfo;
1281 LUID LogonId = {0, 0};
1282 PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1284 HKEY hKey1 = NULL, hKey2 = NULL;
1286 /* Make sure the KFW Libraries are initialized */
1289 DebugEvent0("KFW_Logon_Event - Start");
1291 GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1293 if ( pLogonSessionData ) {
1294 LogonId = pLogonSessionData->LogonId;
1295 DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1297 sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1298 LsaFreeReturnBuffer( pLogonSessionData );
1300 DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1304 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1305 if ( count > sizeof(filename) || count == 0 ) {
1306 GetWindowsDirectory(filename, sizeof(filename));
1309 if ( strlen(filename) + strlen(szLogonId) + 2 <= sizeof(filename) ) {
1310 strcat(filename, "\\");
1311 strcat(filename, szLogonId);
1313 sprintf(commandline, "afscpcc.exe \"%s\"", filename);
1315 GetStartupInfo(&startupinfo);
1316 if (CreateProcessAsUser( pInfo->hToken,
1322 CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1328 WaitForSingleObject(procinfo.hProcess, 30000);
1330 CloseHandle(procinfo.hThread);
1331 CloseHandle(procinfo.hProcess);
1335 DeleteFile(filename);
1337 DebugEvent0("KFW_Logon_Event - End");