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 ZeroMemory(&opt, sizeof(opt));
1053 if (pInfo->UserName && pInfo->Domain) {
1054 char username[MAX_USERNAME_LENGTH] = "";
1055 char domain[MAX_DOMAIN_LENGTH] = "";
1058 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1059 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1060 username, sizeof(username), NULL, NULL);
1062 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1063 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1064 domain, sizeof(domain), NULL, NULL);
1066 GetDomainLogonOptions(NULL, username, domain, &opt);
1069 if (!LogoffPreserveTokens &&
1070 ISLOGONINTEGRATED(opt.LogonOption) &&
1071 ISREMOTE(opt.flags)) {
1073 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1075 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1076 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1078 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1080 DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1085 /* We can't use pInfo->Domain for the domain since in the cross realm case
1086 * this is source domain and not the destination domain.
1088 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1089 WCHAR Domain[64]=L"";
1090 GetLocalShortDomain(Domain, sizeof(Domain));
1091 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1092 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1093 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1097 if (strlen(profileDir)) {
1098 DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1099 if (!IsPathInAfs(profileDir)) {
1100 if (code = ktc_ForgetAllTokens())
1101 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1103 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1105 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1108 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1112 LocalFree(tokenUser);
1115 DebugEvent0("AFS_Logoff_Event - End");
1118 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1120 TCHAR profileDir[1024] = TEXT("");
1122 PTOKEN_USER tokenUser = NULL;
1124 WCHAR szUserW[128] = L"";
1125 char szUserA[128] = "";
1126 char szClient[MAX_PATH];
1127 char szPath[MAX_PATH] = "";
1133 /* Make sure the AFS Libraries are initialized */
1136 DebugEvent0("AFS_Logon_Event - Start");
1138 DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1140 ZeroMemory(&opt, sizeof(opt));
1142 if (pInfo->UserName && pInfo->Domain) {
1143 char username[MAX_USERNAME_LENGTH] = "";
1144 char domain[MAX_DOMAIN_LENGTH] = "";
1147 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1148 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1149 username, sizeof(username), NULL, NULL);
1151 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1152 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1153 domain, sizeof(domain), NULL, NULL);
1155 GetDomainLogonOptions(NULL, username, domain, &opt);
1158 if (!ISLOGONINTEGRATED(opt.LogonOption) || !ISREMOTE(opt.flags)) {
1159 DebugEvent("AFS_Logon_Event - Logon is not integrated or not remote");
1160 goto done_logon_event;
1163 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1165 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1166 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1168 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1170 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1175 /* We can't use pInfo->Domain for the domain since in the cross realm case
1176 * this is source domain and not the destination domain.
1178 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1179 WCHAR Domain[64]=L"";
1180 GetLocalShortDomain(Domain, sizeof(Domain));
1181 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1182 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1183 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1187 if (strlen(profileDir)) {
1188 DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1190 DebugEvent0("AFS_Logon_Event - Unable to load profile");
1193 dwSize = sizeof(szUserA);
1194 if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1195 StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1196 WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1201 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1202 StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1204 DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1206 memset (&nr, 0x00, sizeof(NETRESOURCE));
1207 nr.dwType=RESOURCETYPE_DISK;
1209 nr.lpRemoteName=szPath;
1210 res = WNetAddConnection2(&nr,NULL,szUserA,0);
1212 DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1213 szPath, szUserA,res);
1215 DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1217 DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1220 LocalFree(tokenUser);
1223 DebugEvent0("AFS_Logon_Event - End");
1227 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1229 NTSTATUS Status = 0;
1230 TOKEN_STATISTICS Stats;
1236 *ppSessionData = NULL;
1238 Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1242 Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1243 if ( FAILED(Status) || !ppSessionData )
1249 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1251 WCHAR szUserW[128] = L"";
1252 char szUserA[128] = "";
1253 char szPath[MAX_PATH] = "";
1254 char szLogonId[128] = "";
1257 char commandline[512];
1258 STARTUPINFO startupinfo;
1259 PROCESS_INFORMATION procinfo;
1261 LUID LogonId = {0, 0};
1262 PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1264 HKEY hKey1 = NULL, hKey2 = NULL;
1266 /* Make sure the KFW Libraries are initialized */
1269 DebugEvent0("KFW_Logon_Event - Start");
1271 GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1273 if ( pLogonSessionData ) {
1274 LogonId = pLogonSessionData->LogonId;
1275 DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1277 sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1278 LsaFreeReturnBuffer( pLogonSessionData );
1280 DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1284 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1285 if ( count > sizeof(filename) || count == 0 ) {
1286 GetWindowsDirectory(filename, sizeof(filename));
1289 if ( strlen(filename) + strlen(szLogonId) + 2 <= sizeof(filename) ) {
1290 strcat(filename, "\\");
1291 strcat(filename, szLogonId);
1293 sprintf(commandline, "afscpcc.exe \"%s\"", filename);
1295 GetStartupInfo(&startupinfo);
1296 if (CreateProcessAsUser( pInfo->hToken,
1302 CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1308 WaitForSingleObject(procinfo.hProcess, 30000);
1310 CloseHandle(procinfo.hThread);
1311 CloseHandle(procinfo.hProcess);
1315 DeleteFile(filename);
1317 DebugEvent0("KFW_Logon_Event - End");