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;
38 #define AFS_LOGON_EVENT_NAME TEXT("AFS Logon")
40 void DebugEvent0(char *a)
42 HANDLE h; char *ptbuf[1];
44 if (!ISLOGONTRACE(TraceOption))
47 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
49 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
50 DeregisterEventSource(h);
54 void DebugEvent(char *b,...)
56 HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
59 if (!ISLOGONTRACE(TraceOption))
62 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
64 StringCbVPrintf(buf, MAXBUF_+1,b,marker);
67 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
68 DeregisterEventSource(h);
72 static HANDLE hInitMutex = NULL;
73 static BOOL bInit = FALSE;
75 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
81 case DLL_PROCESS_ATTACH:
82 /* Initialization Mutex */
84 hInitMutex = CreateMutex(NULL, FALSE, NULL);
86 WSAStartup( MAKEWORD(2,2), &wsaData );
89 case DLL_PROCESS_DETACH:
91 CloseHandle(hInitMutex);
96 case DLL_THREAD_ATTACH:
97 case DLL_THREAD_DETACH:
99 /* Everything else succeeds but does nothing. */
106 void AfsLogonInit(void)
108 if ( bInit == FALSE ) {
109 if ( WaitForSingleObject( hInitMutex, INFINITE ) == WAIT_OBJECT_0 ) {
110 /* initAFSDirPath() initializes an array and sets a
111 * flag so that the initialization can only occur
112 * once. No cleanup will be done when the DLL is
113 * unloaded so the initialization will not be
114 * performed again on a subsequent reload
118 /* ka_Init initializes a number of error tables.
119 * and then calls ka_CellConfig() which grabs
120 * an afsconf_dir structure via afsconf_Open().
121 * Upon a second attempt to call ka_CellConfig()
122 * the structure will be released with afsconf_Close()
123 * and then re-opened. Could this corrupt memory?
125 * We only need this if we are not using KFW.
127 if (!KFW_is_available())
131 ReleaseMutex(hInitMutex);
135 CHAR *GenRandomName(CHAR *pbuf)
138 srand( (unsigned)time( NULL ) );
139 for (i=0;i<MAXRANDOMNAMELEN-1;i++)
140 pbuf[i]='a'+(rand() % 26);
141 pbuf[MAXRANDOMNAMELEN-1]=0;
145 BOOLEAN AFSWillAutoStart(void)
150 BOOLEAN result = FALSE;
151 LPQUERY_SERVICE_CONFIG pConfig = NULL;
155 /* Open services manager */
156 scm = OpenSCManager(NULL, NULL, GENERIC_READ);
157 if (!scm) return FALSE;
159 /* Open AFSD service */
160 svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
164 /* Query AFSD service config, first just to get buffer size */
165 /* Expected to fail, so don't test return value */
166 (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
167 status = GetLastError();
168 if (status != ERROR_INSUFFICIENT_BUFFER)
171 /* Allocate buffer */
172 pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
176 /* Query AFSD service config, this time for real */
177 flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
181 /* Is it autostart? */
182 if (pConfig->dwStartType < SERVICE_DEMAND_START)
188 CloseServiceHandle(svc);
190 CloseServiceHandle(scm);
195 DWORD MapAuthError(DWORD code)
198 /* Unfortunately, returning WN_NO_NETWORK results in the MPR abandoning
199 * logon scripts for all credential managers, although they will still
200 * receive logon notifications. Since we don't want this, we return
201 * WN_SUCCESS. This is highly undesirable, but we also don't want to
202 * break other network providers.
206 return WN_NO_NETWORK; */
207 default: return WN_SUCCESS;
211 DWORD APIENTRY NPGetCaps(DWORD index)
215 /* Don't have our own type; use somebody else's. */
216 return WNNC_NET_SUN_PC_NFS;
219 /* Say we are already started, even though we might wait after we receive NPLogonNotify */
228 NetUserGetProfilePath( LPCWSTR Domain, LPCWSTR UserName, char * profilePath,
229 DWORD profilePathLen )
232 LPWSTR ServerName = NULL;
233 LPUSER_INFO_3 p3 = NULL;
235 NetGetAnyDCName(NULL, Domain, (LPBYTE *)&ServerName);
236 /* if NetGetAnyDCName fails, ServerName == NULL
237 * NetUserGetInfo will obtain local user information
239 code = NetUserGetInfo(ServerName, UserName, 3, (LPBYTE *)&p3);
240 if (code == NERR_Success)
242 code = NERR_UserNotFound;
244 if (p3->usri3_profile) {
245 DWORD len = lstrlenW(p3->usri3_profile);
247 /* Convert From Unicode to ANSI (UTF-8 for future) */
248 len = len < profilePathLen ? len : profilePathLen - 1;
249 WideCharToMultiByte(CP_UTF8, 0, p3->usri3_profile, len, profilePath, len, NULL, NULL);
250 profilePath[len] = '\0';
254 NetApiBufferFree(p3);
258 NetApiBufferFree(ServerName);
262 BOOL IsServiceRunning (void)
264 SERVICE_STATUS Status;
266 memset (&Status, 0x00, sizeof(Status));
267 Status.dwCurrentState = SERVICE_STOPPED;
269 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
272 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
274 QueryServiceStatus (hService, &Status);
275 CloseServiceHandle (hService);
278 CloseServiceHandle (hManager);
280 DebugEvent("AFS AfsLogon - Test Service Running Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
281 return (Status.dwCurrentState == SERVICE_RUNNING);
284 BOOL IsServiceStartPending (void)
286 SERVICE_STATUS Status;
288 memset (&Status, 0x00, sizeof(Status));
289 Status.dwCurrentState = SERVICE_STOPPED;
291 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
294 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
296 QueryServiceStatus (hService, &Status);
297 CloseServiceHandle (hService);
300 CloseServiceHandle (hManager);
302 DebugEvent("AFS AfsLogon - Test Service Start Pending Return Code[%x] ?Start Pending[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_START_PENDING));
303 return (Status.dwCurrentState == SERVICE_START_PENDING);
306 /* LOOKUPKEYCHAIN: macro to look up the value in the list of keys in order until it's found
307 v:variable to receive value (reference type)
309 d:default, in case the value isn't on any of the keys
311 #define LOOKUPKEYCHAIN(v,t,d,n) \
313 rv = ~ERROR_SUCCESS; \
316 dwSize = sizeof(v); \
317 rv = RegQueryValueEx(hkDom, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
318 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDom with type [%d]", dwType); \
320 if(hkDoms && (rv != ERROR_SUCCESS || dwType != t)) { \
321 dwSize = sizeof(v); \
322 rv = RegQueryValueEx(hkDoms, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
323 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkDoms with type [%d]", dwType); \
325 if(hkNp && (rv != ERROR_SUCCESS || dwType != t)) { \
326 dwSize = sizeof(v); \
327 rv = RegQueryValueEx(hkNp, n, 0, &dwType, (LPBYTE) &(v), &dwSize); \
328 if(rv == ERROR_SUCCESS) DebugEvent(#v " found in hkNp with type [%d]", dwType); \
330 if(rv != ERROR_SUCCESS || dwType != t) { \
332 DebugEvent(#v " being set to default"); \
336 /* Get domain specific configuration info. We are returning void because if anything goes wrong
337 we just return defaults.
340 GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
341 HKEY hkParm = NULL; /* Service parameter */
342 HKEY hkNp = NULL; /* network provider key */
343 HKEY hkDoms = NULL; /* domains key */
344 HKEY hkDom = NULL; /* DOMAINS/domain key */
350 char computerName[MAX_COMPUTERNAME_LENGTH + 1];
353 memset(opt, 0, sizeof(LogonOptions_t));
355 DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
356 /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
357 opt->flags = LOGON_FLAG_REMOTE;
359 dwSize = MAX_COMPUTERNAME_LENGTH;
360 if(GetComputerName(computerName, &dwSize)) {
361 if(!stricmp(computerName, domain)) {
362 effDomain = "LOCALHOST";
363 opt->flags = LOGON_FLAG_LOCAL;
371 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, KEY_READ, &hkParm );
372 if(rv != ERROR_SUCCESS) {
374 DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
377 rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PROVIDER_SUBKEY, 0, KEY_READ, &hkNp );
378 if(rv != ERROR_SUCCESS) {
380 DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
384 rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
385 if( rv != ERROR_SUCCESS ) {
387 DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
391 if(hkDoms && effDomain) {
392 rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
393 if( rv != ERROR_SUCCESS ) {
395 DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
396 /* If none of the domains match, we shouldn't use the domain key either */
401 DebugEvent("Not opening domain key");
403 /* Each individual can either be specified on the domain key, the domains key or in the
404 net provider key. They fail over in that order. If none is found, we just use the
408 LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
410 /* FailLoginsSilently */
411 dwSize = sizeof(dwDummy);
412 rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
413 if (rv != ERROR_SUCCESS)
414 LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
415 opt->failSilently = !!dwDummy;
418 LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
421 LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
423 opt->logonScript = NULL;
426 if(!ISLOGONINTEGRATED(opt->LogonOption)) {
427 goto cleanup; /* no need to lookup the logon script */
430 /* come up with SMB username */
431 if(ISHIGHSECURITY(opt->LogonOption)) {
432 opt->smbName = malloc( MAXRANDOMNAMELEN );
433 GenRandomName(opt->smbName);
434 } else if (lpLogonId) {
435 /* username and domain for logon session is not necessarily the same as
436 username and domain passed into network provider. */
437 PSECURITY_LOGON_SESSION_DATA plsd;
438 char lsaUsername[MAX_USERNAME_LENGTH];
439 char lsaDomain[MAX_DOMAIN_LENGTH];
442 LsaGetLogonSessionData(lpLogonId, &plsd);
444 UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
445 UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
447 DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
449 if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
454 if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
461 opt->smbName = malloc(len);
463 StringCbCopy(opt->smbName, len, lsaDomain);
464 StringCbCat(opt->smbName, len, "\\");
465 StringCbCat(opt->smbName, len, lsaUsername);
467 strlwr(opt->smbName);
470 LsaFreeReturnBuffer(plsd);
474 DebugEvent("No LUID given. Constructing username using [%s] and [%s]",
477 len = strlen(username) + strlen(domain) + 2;
479 opt->smbName = malloc(len);
481 StringCbCopy(opt->smbName, len, username);
482 StringCbCat(opt->smbName, len, "\\");
483 StringCbCat(opt->smbName, len, domain);
485 strlwr(opt->smbName);
488 DebugEvent("Looking up logon script");
490 /* First find out where the key is */
495 rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
496 if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
498 DebugEvent("Located logon script in hkDom");
501 rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
502 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
504 DebugEvent("Located logon script in hkDoms");
506 /* Note that the LogonScript in the NP key is only used if we are doing high security. */
507 else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
508 rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
509 if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
511 DebugEvent("Located logon script in hkNp");
515 WCHAR *regscript = NULL;
516 WCHAR *regexscript = NULL;
517 WCHAR *regexuscript = NULL;
518 WCHAR *wuname = NULL;
523 StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
526 wuname = malloc(len * sizeof(WCHAR));
527 MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,(int)(len*sizeof(WCHAR)));
529 DebugEvent("Username is set for [%S]", wuname);
531 /* dwSize still has the size of the required buffer in bytes. */
532 regscript = malloc(dwSize);
533 rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
534 if(rv != ERROR_SUCCESS) {/* what the ..? */
535 DebugEvent("Can't look up logon script [%d]",rv);
536 goto doneLogonScript;
539 DebugEvent("Found logon script [%S]", regscript);
541 if(dwType == REG_EXPAND_SZ) {
544 dwSize += MAX_PATH * sizeof(WCHAR); /* make room for environment expansion. */
545 regexscript = malloc(dwSize);
546 dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
548 regscript = regexscript;
550 if(dwReq > (dwSize / sizeof(WCHAR))) {
551 DebugEvent("Overflow while expanding environment strings.");
552 goto doneLogonScript;
556 DebugEvent("After expanding env strings [%S]", regscript);
558 if(wcsstr(regscript, L"%s")) {
559 dwSize += (DWORD)(len * sizeof(WCHAR)); /* make room for username expansion */
560 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
561 hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
563 regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
564 hr = StringCbCopyW(regexuscript, dwSize, regscript);
567 DebugEvent("After expanding username [%S]", regexuscript);
570 opt->logonScript = regexuscript;
572 LocalFree(regexuscript);
575 if(wuname) free(wuname);
576 if(regscript) free(regscript);
577 if(regexscript) free(regexscript);
580 DebugEvent("Looking up TheseCells");
582 /* First find out where the key is */
587 rv = RegQueryValueEx(hkDom, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
588 if (rv == ERROR_SUCCESS && dwType == REG_MULTI_SZ) {
590 DebugEvent("Located TheseCells in hkDom");
592 rv = RegQueryValueEx(hkDoms, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
593 if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
595 DebugEvent("Located TheseCells in hkDoms");
597 rv = RegQueryValueEx(hkNp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
598 if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
600 DebugEvent("Located TheseCells in hkNp");
606 /* dwSize still has the size of the required buffer in bytes. */
607 thesecells = malloc(dwSize);
608 rv = RegQueryValueEx(hkTemp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, (LPBYTE) thesecells, &dwSize);
609 if(rv != ERROR_SUCCESS) {/* what the ..? */
610 DebugEvent("Can't look up TheseCells [%d]",rv);
614 DebugEvent("Found TheseCells [%s]", thesecells);
615 opt->theseCells = thesecells;
622 if(hkNp) RegCloseKey(hkNp);
623 if(hkDom) RegCloseKey(hkDom);
624 if(hkDoms) RegCloseKey(hkDoms);
625 if(hkParm) RegCloseKey(hkParm);
628 #undef LOOKUPKEYCHAIN
630 /* Try to find out which cell the given path is in. We must retain
631 the contents of *cell in case of failure. *cell is assumed to be
632 at least cellLen chars */
633 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
634 struct ViceIoctl blob;
635 char tcell[MAX_PATH];
639 blob.out_size = MAX_PATH;
642 code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
645 strncpy(cell, tcell, cellLen);
646 cell[cellLen - 1] = '\0';
654 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
658 GetCPInfo(CP_ACP, &CodePageInfo);
660 if (CodePageInfo.MaxCharSize > 1)
661 // Only supporting non-Unicode strings
664 if (uInputString.Buffer && ((LPBYTE) uInputString.Buffer)[1] == '\0')
666 // Looks like unicode, better translate it
667 // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
668 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
669 lpszOutputString, nOutStringLen-1, NULL, NULL);
670 lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
674 lpszOutputString[0] = '\0';
676 } // UnicodeStringToANSI
678 DWORD APIENTRY NPLogonNotify(
680 LPCWSTR lpAuthentInfoType,
681 LPVOID lpAuthentInfo,
682 LPCWSTR lpPreviousAuthentInfoType,
683 LPVOID lpPreviousAuthentInfo,
684 LPWSTR lpStationName,
685 LPVOID StationHandle,
686 LPWSTR *lpLogonScript)
688 char uname[MAX_USERNAME_LENGTH]="";
689 char password[MAX_PASSWORD_LENGTH]="";
690 char logonDomain[MAX_DOMAIN_LENGTH]="";
691 char cell[256]="<non-integrated logon>";
692 char homePath[MAX_PATH]="";
693 char szLogonId[128] = "";
695 MSV1_0_INTERACTIVE_LOGON *IL;
697 DWORD code = 0, code2;
705 DWORD LSPtype, LSPsize;
708 HWND hwndOwner = (HWND)StationHandle;
710 BOOLEAN afsWillAutoStart;
712 BOOLEAN lowercased_name = TRUE;
714 LogonOptions_t opt; /* domain specific logon options */
718 /* Are we interactive? */
719 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
721 /* Do not do anything if the logon session is not interactive. */
725 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
726 0, KEY_QUERY_VALUE, &NPKey);
727 LSPsize=sizeof(TraceOption);
728 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
729 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
733 DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart);
735 /* Make sure the AFS Libraries are initialized */
738 /* Initialize Logon Script to none */
741 /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for
744 if ( wcscmp(lpAuthentInfoType,L"MSV1_0:Interactive") &&
745 wcscmp(lpAuthentInfoType,L"Kerberos:Interactive") )
747 DebugEvent("Unsupported Authentication Info Type: %S",
752 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
754 /* Convert from Unicode to ANSI */
756 /*TODO: Use SecureZeroMemory to erase passwords */
757 if (!UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH) ||
758 !UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH) ||
759 !UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH))
762 /* Make sure AD-DOMANS sent from login that is sent to us is striped */
763 ctemp = strchr(uname, '@');
764 if (ctemp) *ctemp = 0;
766 /* is the name all lowercase? */
767 for ( ctemp = uname; *ctemp ; ctemp++) {
768 if ( !islower(*ctemp) ) {
769 lowercased_name = FALSE;
778 GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
779 retryInterval = opt.retryInterval;
780 sleepInterval = opt.sleepInterval;
781 *lpLogonScript = opt.logonScript;
783 if (retryInterval < sleepInterval)
784 sleepInterval = retryInterval;
786 DebugEvent("Got logon script: %S",opt.logonScript);
788 afsWillAutoStart = AFSWillAutoStart();
790 DebugEvent("LogonOption[%x], Service AutoStart[%d]",
791 opt.LogonOption,afsWillAutoStart);
793 /* Check for zero length password if integrated logon*/
794 if ( ISLOGONINTEGRATED(opt.LogonOption) ) {
795 if ( password[0] == 0 ) {
796 DebugEvent("Password is the empty string");
798 reason = "zero length password is illegal";
802 /* Get cell name if doing integrated logon.
803 We might overwrite this if we are logging into an AD realm and we find out that
804 the user's home dir is in some other cell. */
805 DebugEvent("About to call cm_GetRootCellName(%s)",cell);
806 code = cm_GetRootCellName(cell);
808 DebugEvent("Unable to obtain Root Cell");
810 reason = "unknown cell";
813 DebugEvent("Cell is %s",cell);
816 /* We get the user's home directory path, if applicable, though we can't lookup the
817 cell right away because the client service may not have started yet. This call
818 also sets the AD_REALM flag in opt.flags if applicable. */
819 if (ISREMOTE(opt.flags)) {
820 DebugEvent("Is Remote");
821 GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
825 /* loop until AFS is started. */
826 if (afsWillAutoStart) {
827 while (IsServiceRunning() || IsServiceStartPending()) {
828 DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
829 opt.LogonOption,afsWillAutoStart);
831 if (ISADREALM(opt.flags)) {
832 code = GetFileCellName(homePath,cell,256);
834 DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
836 /* Don't bail out if GetFileCellName failed.
837 * The home dir may not be in AFS after all.
842 /* if Integrated Logon */
843 if (ISLOGONINTEGRATED(opt.LogonOption))
845 if ( KFW_is_available() ) {
846 SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
847 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
848 SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL);
849 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
850 uname,opt.smbName,cell,code);
851 if (code == 0 && opt.theseCells) {
852 char * principal, *p;
855 StringCchLength(cell, MAX_DOMAIN_LENGTH, &tlen);
857 StringCchLength(uname, MAX_USERNAME_LENGTH, &tlen);
860 /* tlen is now the length of uname in characters */
861 principal = (char *)malloc(len * sizeof(char));
863 StringCchCopy(principal, len, uname);
864 p = principal + tlen;
866 StringCchCopy(p, len - tlen - 1, cell);
873 SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
874 code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
875 SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, NULL);
876 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
877 principal,opt.smbName,p,code2);
884 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
885 uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
887 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2 Code[%x] uname[%s] smbname=[%s] Cell[%s] PwExp=[%d] Reason=[%s]",
888 code,uname,opt.smbName,cell,pw_exp,reason?reason:"");
890 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
891 for ( ctemp = uname; *ctemp ; ctemp++) {
892 *ctemp = tolower(*ctemp);
894 lowercased_name = TRUE;
898 /* is service started yet?*/
900 /* If we've failed because the client isn't running yet and the
901 * client is set to autostart (and therefore it makes sense for
902 * us to wait for it to start) then sleep a while and try again.
903 * If the error was something else, then give up. */
904 if (code != KTC_NOCM && code != KTC_NOCMRPC)
908 /*JUST check to see if its running*/
909 if (IsServiceRunning())
911 if (!IsServiceStartPending()) {
913 reason = "AFS Service start failed";
918 /* If the retry interval has expired and we still aren't
919 * logged in, then just give up if we are not in interactive
920 * mode or the failSilently flag is set, otherwise let the
921 * user know we failed and give them a chance to try again. */
922 if (retryInterval <= 0) {
923 reason = "AFS not running";
924 if (!interactive || opt.failSilently)
926 flag = MessageBox(hwndOwner,
927 "AFS is still starting. Retry?",
929 MB_ICONQUESTION | MB_RETRYCANCEL);
930 if (flag == IDCANCEL)
933 /* Wait just a little while and try again */
934 retryInterval = opt.retryInterval;
938 Sleep(sleepInterval * 1000);
939 retryInterval -= sleepInterval;
942 DebugEvent("while loop exited");
944 /* remove any kerberos 5 tickets currently held by the SYSTEM account
948 if (ISLOGONINTEGRATED(opt.LogonOption) && KFW_is_available()) {
950 sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
951 KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
953 KFW_AFS_destroy_tickets_for_principal(uname);
961 StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
963 if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
964 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
966 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
968 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
970 DeregisterEventSource(h);
972 code = MapAuthError(code);
975 if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
978 LocalFree(*lpLogonScript);
979 *lpLogonScript = NULL;
980 if (!afsWillAutoStart) // its not running, so if not autostart or integrated logon then just skip
985 if (opt.theseCells) free(opt.theseCells);
986 if (opt.smbName) free(opt.smbName);
988 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
992 DWORD APIENTRY NPPasswordChangeNotify(
993 LPCWSTR lpAuthentInfoType,
994 LPVOID lpAuthentInfo,
995 LPCWSTR lpPreviousAuthentInfoType,
996 LPVOID lpPreviousAuthentInfo,
997 LPWSTR lpStationName,
998 LPVOID StationHandle,
1001 BOOLEAN interactive;
1003 /* Are we interactive? */
1004 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
1006 /* Do not do anything if the logon session is not interactive. */
1010 /* Make sure the AFS Libraries are initialized */
1013 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
1017 #include <userenv.h>
1019 #include <afs/vice.h>
1020 #include <afs/fs_utils.h>
1022 BOOL IsPathInAfs(const CHAR *strPath)
1025 struct ViceIoctl blob;
1029 blob.out_size = 2048;
1032 code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
1039 typedef struct _WLX_NOTIFICATION_INFO {
1044 PWSTR WindowStation;
1047 PFNMSGECALLBACK pStatusCallback;
1048 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
1051 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
1053 DWORD LSPtype, LSPsize;
1056 /* Make sure the AFS Libraries are initialized */
1059 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1060 0, KEY_QUERY_VALUE, &NPKey);
1061 LSPsize=sizeof(TraceOption);
1062 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
1063 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
1065 RegCloseKey (NPKey);
1066 DebugEvent0("AFS_Startup_Event");
1069 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
1072 TCHAR profileDir[1024] = TEXT("");
1074 PTOKEN_USER tokenUser = NULL;
1076 DWORD LSPtype, LSPsize;
1078 DWORD LogoffPreserveTokens = 0;
1081 /* Make sure the AFS Libraries are initialized */
1084 DebugEvent0("AFS_Logoff_Event - Start");
1086 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1087 0, KEY_QUERY_VALUE, &NPKey);
1088 LSPsize=sizeof(LogoffPreserveTokens);
1089 RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
1090 &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
1091 RegCloseKey (NPKey);
1093 if (!LogoffPreserveTokens) {
1094 memset(&opt, 0, sizeof(LogonOptions_t));
1096 if (pInfo->UserName && pInfo->Domain) {
1097 char username[MAX_USERNAME_LENGTH] = "";
1098 char domain[MAX_DOMAIN_LENGTH] = "";
1101 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1102 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1103 username, sizeof(username), NULL, NULL);
1105 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1106 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1107 domain, sizeof(domain), NULL, NULL);
1109 GetDomainLogonOptions(NULL, username, domain, &opt);
1112 if (ISREMOTE(opt.flags)) {
1113 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1115 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1116 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1118 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1120 DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1125 /* We can't use pInfo->Domain for the domain since in the cross realm case
1126 * this is source domain and not the destination domain.
1128 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1129 WCHAR Domain[64]=L"";
1130 GetLocalShortDomain(Domain, sizeof(Domain));
1131 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1132 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1133 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1137 if (strlen(profileDir)) {
1138 DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1139 if (!IsPathInAfs(profileDir)) {
1140 if (code = ktc_ForgetAllTokens())
1141 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1143 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1145 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1148 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1152 LocalFree(tokenUser);
1154 DebugEvent0("AFS_Logoff_Event - Local Logon");
1155 if (code = ktc_ForgetAllTokens())
1156 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1158 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1161 DebugEvent0("AFS_Logoff_Event - Preserving Tokens");
1164 DebugEvent0("AFS_Logoff_Event - End");
1167 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1169 TCHAR profileDir[1024] = TEXT("");
1171 PTOKEN_USER tokenUser = NULL;
1173 WCHAR szUserW[128] = L"";
1174 char szUserA[128] = "";
1175 char szClient[MAX_PATH];
1176 char szPath[MAX_PATH] = "";
1182 /* Make sure the AFS Libraries are initialized */
1185 DebugEvent0("AFS_Logon_Event - Start");
1187 DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1189 memset(&opt, 0, sizeof(LogonOptions_t));
1191 if (pInfo->UserName && pInfo->Domain) {
1192 char username[MAX_USERNAME_LENGTH] = "";
1193 char domain[MAX_DOMAIN_LENGTH] = "";
1196 DebugEvent0("AFS_Logon_Event - pInfo UserName and Domain");
1198 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1199 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1200 username, sizeof(username), NULL, NULL);
1202 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1203 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1204 domain, sizeof(domain), NULL, NULL);
1206 DebugEvent0("AFS_Logon_Event - Calling GetDomainLogonOptions");
1207 GetDomainLogonOptions(NULL, username, domain, &opt);
1209 if (!pInfo->UserName)
1210 DebugEvent0("AFS_Logon_Event - No pInfo->UserName");
1212 DebugEvent0("AFS_Logon_Event - No pInfo->Domain");
1215 DebugEvent("AFS_Logon_Event - opt.LogonOption = %lX opt.flags = %lX",
1216 opt.LogonOption, opt.flags);
1218 if (!ISLOGONINTEGRATED(opt.LogonOption) || !ISREMOTE(opt.flags)) {
1219 DebugEvent0("AFS_Logon_Event - Logon is not integrated or not remote");
1220 goto done_logon_event;
1223 DebugEvent0("AFS_Logon_Event - Calling GetTokenInformation");
1225 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1227 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1228 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1230 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1232 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1237 /* We can't use pInfo->Domain for the domain since in the cross realm case
1238 * this is source domain and not the destination domain.
1240 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1241 WCHAR Domain[64]=L"";
1242 GetLocalShortDomain(Domain, sizeof(Domain));
1243 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1244 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1245 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1249 if (strlen(profileDir)) {
1250 DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1252 DebugEvent0("AFS_Logon_Event - Unable to load profile");
1256 dwSize = sizeof(szUserA);
1257 if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1258 StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1259 WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1264 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1265 StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1267 DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1269 memset (&nr, 0x00, sizeof(NETRESOURCE));
1270 nr.dwType=RESOURCETYPE_DISK;
1272 nr.lpRemoteName=szPath;
1273 res = WNetAddConnection2(&nr,NULL,szUserA,0);
1275 DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1276 szPath, szUserA,res);
1278 DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1280 DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1283 LocalFree(tokenUser);
1285 DebugEvent0("AFS_Logon_Event - End");
1289 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1291 NTSTATUS Status = 0;
1292 TOKEN_STATISTICS Stats;
1298 *ppSessionData = NULL;
1300 Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1304 Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1305 if ( FAILED(Status) || !ppSessionData )
1311 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1314 WCHAR szUserW[128] = L"";
1315 char szUserA[128] = "";
1316 char szPath[MAX_PATH] = "";
1317 char szLogonId[128] = "";
1319 char filename[MAX_PATH] = "";
1320 char newfilename[MAX_PATH] = "";
1321 char commandline[MAX_PATH+256] = "";
1322 STARTUPINFO startupinfo;
1323 PROCESS_INFORMATION procinfo;
1324 HANDLE hf = INVALID_HANDLE_VALUE;
1326 LUID LogonId = {0, 0};
1327 PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1329 HKEY hKey1 = NULL, hKey2 = NULL;
1331 /* Make sure the KFW Libraries are initialized */
1334 DebugEvent0("KFW_Logon_Event - Start");
1336 GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1338 if ( pLogonSessionData ) {
1339 LogonId = pLogonSessionData->LogonId;
1340 DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1342 sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1343 LsaFreeReturnBuffer( pLogonSessionData );
1345 DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1349 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1350 if ( count > sizeof(filename) || count == 0 ) {
1351 GetWindowsDirectory(filename, sizeof(filename));
1354 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1355 if ( count > sizeof(filename) || count == 0 ) {
1356 GetWindowsDirectory(filename, sizeof(filename));
1359 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) {
1360 DebugEvent0("KFW_Logon_Event - filename too long");
1364 strcat(filename, "\\");
1365 strcat(filename, szLogonId);
1367 hf = CreateFile(filename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING,
1368 FILE_ATTRIBUTE_NORMAL, NULL);
1369 if (hf == INVALID_HANDLE_VALUE) {
1370 DebugEvent0("KFW_Logon_Event - file cannot be opened");
1375 if (KFW_AFS_set_file_cache_dacl(filename, pInfo->hToken)) {
1376 DebugEvent0("KFW_Logon_Event - unable to set dacl");
1377 DeleteFile(filename);
1381 if (KFW_AFS_obtain_user_temp_directory(pInfo->hToken, newfilename, sizeof(newfilename))) {
1382 DebugEvent0("KFW_Logon_Event - unable to obtain temp directory");
1386 if ( strlen(newfilename) + strlen(szLogonId) + 2 > sizeof(newfilename) ) {
1387 DebugEvent0("KFW_Logon_Event - new filename too long");
1391 strcat(newfilename, "\\");
1392 strcat(newfilename, szLogonId);
1394 if (!MoveFileEx(filename, newfilename,
1395 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
1396 DebugEvent("KFW_Logon_Event - MoveFileEx failed GLE = 0x%x", GetLastError());
1400 sprintf(commandline, "afscpcc.exe \"%s\"", newfilename);
1402 GetStartupInfo(&startupinfo);
1403 if (CreateProcessAsUser( pInfo->hToken,
1409 CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1415 DebugEvent("KFW_Logon_Event - CommandLine %s", commandline);
1417 WaitForSingleObject(procinfo.hProcess, 30000);
1419 CloseHandle(procinfo.hThread);
1420 CloseHandle(procinfo.hProcess);
1422 DebugEvent0("KFW_Logon_Event - CreateProcessFailed");
1425 DeleteFile(filename);
1427 DebugEvent0("KFW_Logon_Event - End");