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)
79 case DLL_PROCESS_ATTACH:
80 /* Initialization Mutex */
82 hInitMutex = CreateMutex(NULL, FALSE, NULL);
83 SetEnvironmentVariable(DO_NOT_REGISTER_VARNAME, "");
87 case DLL_PROCESS_DETACH:
88 /* do nothing on unload because we might
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 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
719 0, KEY_QUERY_VALUE, &NPKey);
720 LSPsize=sizeof(TraceOption);
721 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
722 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
726 DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart);
728 /* Make sure the AFS Libraries are initialized */
731 /* Initialize Logon Script to none */
734 /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for
737 if ( wcscmp(lpAuthentInfoType,L"MSV1_0:Interactive") &&
738 wcscmp(lpAuthentInfoType,L"Kerberos:Interactive") )
740 DebugEvent("Unsupported Authentication Info Type: %S",
745 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
747 /* Are we interactive? */
748 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
750 /* Convert from Unicode to ANSI */
752 /*TODO: Use SecureZeroMemory to erase passwords */
753 if (!UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH) ||
754 !UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH) ||
755 !UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH))
758 /* Make sure AD-DOMANS sent from login that is sent to us is striped */
759 ctemp = strchr(uname, '@');
760 if (ctemp) *ctemp = 0;
762 /* is the name all lowercase? */
763 for ( ctemp = uname; *ctemp ; ctemp++) {
764 if ( !islower(*ctemp) ) {
765 lowercased_name = FALSE;
774 GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
775 retryInterval = opt.retryInterval;
776 sleepInterval = opt.sleepInterval;
777 *lpLogonScript = opt.logonScript;
779 if (retryInterval < sleepInterval)
780 sleepInterval = retryInterval;
782 DebugEvent("Got logon script: %S",opt.logonScript);
784 afsWillAutoStart = AFSWillAutoStart();
786 DebugEvent("LogonOption[%x], Service AutoStart[%d]",
787 opt.LogonOption,afsWillAutoStart);
789 /* Check for zero length password if integrated logon*/
790 if ( ISLOGONINTEGRATED(opt.LogonOption) ) {
791 if ( password[0] == 0 ) {
792 DebugEvent("Password is the empty string");
794 reason = "zero length password is illegal";
798 /* Get cell name if doing integrated logon.
799 We might overwrite this if we are logging into an AD realm and we find out that
800 the user's home dir is in some other cell. */
801 DebugEvent("About to call cm_GetRootCellName(%s)",cell);
802 code = cm_GetRootCellName(cell);
804 DebugEvent("Unable to obtain Root Cell");
806 reason = "unknown cell";
809 DebugEvent("Cell is %s",cell);
812 /* We get the user's home directory path, if applicable, though we can't lookup the
813 cell right away because the client service may not have started yet. This call
814 also sets the AD_REALM flag in opt.flags if applicable. */
815 if (ISREMOTE(opt.flags)) {
816 DebugEvent("Is Remote");
817 GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
821 /* loop until AFS is started. */
822 if (afsWillAutoStart) {
823 while (IsServiceRunning() || IsServiceStartPending()) {
824 DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
825 opt.LogonOption,afsWillAutoStart);
827 if (ISADREALM(opt.flags)) {
828 code = GetFileCellName(homePath,cell,256);
830 DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
832 /* Don't bail out if GetFileCellName failed.
833 * The home dir may not be in AFS after all.
838 /* if Integrated Logon */
839 if (ISLOGONINTEGRATED(opt.LogonOption))
841 if ( KFW_is_available() ) {
842 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
843 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
844 uname,opt.smbName,cell,code);
845 if (code == 0 && opt.theseCells) {
846 char * principal, *p;
849 StringCchLength(cell, MAX_DOMAIN_LENGTH, &tlen);
851 StringCchLength(uname, MAX_USERNAME_LENGTH, &tlen);
854 /* tlen is now the length of uname in characters */
855 principal = (char *)malloc(len * sizeof(char));
857 StringCchCopy(principal, len, uname);
858 p = principal + tlen;
860 StringCchCopy(p, len - tlen - 1, cell);
867 code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
868 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
869 principal,opt.smbName,p,code2);
876 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
877 uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
879 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2 Code[%x] uname[%s] smbname=[%s] Cell[%s] PwExp=[%d] Reason=[%s]",
880 code,uname,opt.smbName,cell,pw_exp,reason?reason:"");
882 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
883 for ( ctemp = uname; *ctemp ; ctemp++) {
884 *ctemp = tolower(*ctemp);
886 lowercased_name = TRUE;
890 /* is service started yet?*/
892 /* If we've failed because the client isn't running yet and the
893 * client is set to autostart (and therefore it makes sense for
894 * us to wait for it to start) then sleep a while and try again.
895 * If the error was something else, then give up. */
896 if (code != KTC_NOCM && code != KTC_NOCMRPC)
900 /*JUST check to see if its running*/
901 if (IsServiceRunning())
903 if (!IsServiceStartPending()) {
905 reason = "AFS Service start failed";
910 /* If the retry interval has expired and we still aren't
911 * logged in, then just give up if we are not in interactive
912 * mode or the failSilently flag is set, otherwise let the
913 * user know we failed and give them a chance to try again. */
914 if (retryInterval <= 0) {
915 reason = "AFS not running";
916 if (!interactive || opt.failSilently)
918 flag = MessageBox(hwndOwner,
919 "AFS is still starting. Retry?",
921 MB_ICONQUESTION | MB_RETRYCANCEL);
922 if (flag == IDCANCEL)
925 /* Wait just a little while and try again */
926 retryInterval = opt.retryInterval;
930 Sleep(sleepInterval * 1000);
931 retryInterval -= sleepInterval;
934 DebugEvent("while loop exited");
935 /* remove any kerberos 5 tickets currently held by the SYSTEM account
938 if (ISLOGONINTEGRATED(opt.LogonOption) && KFW_is_available()) {
939 sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
940 KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
942 KFW_AFS_destroy_tickets_for_principal(uname);
950 StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
952 if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
953 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
955 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
957 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
959 DeregisterEventSource(h);
961 code = MapAuthError(code);
964 if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
967 LocalFree(*lpLogonScript);
968 *lpLogonScript = NULL;
969 if (!afsWillAutoStart) // its not running, so if not autostart or integrated logon then just skip
974 if (opt.theseCells) free(opt.theseCells);
975 if (opt.smbName) free(opt.smbName);
977 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
981 DWORD APIENTRY NPPasswordChangeNotify(
982 LPCWSTR lpAuthentInfoType,
983 LPVOID lpAuthentInfo,
984 LPCWSTR lpPreviousAuthentInfoType,
985 LPVOID lpPreviousAuthentInfo,
986 LPWSTR lpStationName,
987 LPVOID StationHandle,
990 /* Make sure the AFS Libraries are initialized */
993 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
999 #include <afs/vice.h>
1000 #include <afs/fs_utils.h>
1002 BOOL IsPathInAfs(const CHAR *strPath)
1005 struct ViceIoctl blob;
1009 blob.out_size = 2048;
1012 code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
1019 typedef struct _WLX_NOTIFICATION_INFO {
1024 PWSTR WindowStation;
1027 PFNMSGECALLBACK pStatusCallback;
1028 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
1031 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
1033 DWORD LSPtype, LSPsize;
1036 /* Make sure the AFS Libraries are initialized */
1039 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1040 0, KEY_QUERY_VALUE, &NPKey);
1041 LSPsize=sizeof(TraceOption);
1042 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
1043 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
1045 RegCloseKey (NPKey);
1046 DebugEvent0("AFS_Startup_Event");
1049 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
1052 TCHAR profileDir[1024] = TEXT("");
1054 PTOKEN_USER tokenUser = NULL;
1056 DWORD LSPtype, LSPsize;
1058 DWORD LogoffPreserveTokens = 0;
1061 /* Make sure the AFS Libraries are initialized */
1064 DebugEvent0("AFS_Logoff_Event - Start");
1066 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1067 0, KEY_QUERY_VALUE, &NPKey);
1068 LSPsize=sizeof(LogoffPreserveTokens);
1069 RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
1070 &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
1071 RegCloseKey (NPKey);
1073 if (!LogoffPreserveTokens) {
1074 memset(&opt, 0, sizeof(LogonOptions_t));
1076 if (pInfo->UserName && pInfo->Domain) {
1077 char username[MAX_USERNAME_LENGTH] = "";
1078 char domain[MAX_DOMAIN_LENGTH] = "";
1081 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1082 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1083 username, sizeof(username), NULL, NULL);
1085 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1086 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1087 domain, sizeof(domain), NULL, NULL);
1089 GetDomainLogonOptions(NULL, username, domain, &opt);
1092 if (ISREMOTE(opt.flags)) {
1093 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1095 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1096 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1098 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1100 DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1105 /* We can't use pInfo->Domain for the domain since in the cross realm case
1106 * this is source domain and not the destination domain.
1108 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1109 WCHAR Domain[64]=L"";
1110 GetLocalShortDomain(Domain, sizeof(Domain));
1111 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1112 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1113 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1117 if (strlen(profileDir)) {
1118 DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1119 if (!IsPathInAfs(profileDir)) {
1120 if (code = ktc_ForgetAllTokens())
1121 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1123 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1125 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1128 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1132 LocalFree(tokenUser);
1134 DebugEvent0("AFS_Logoff_Event - Local Logon");
1135 if (code = ktc_ForgetAllTokens())
1136 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1138 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1141 DebugEvent0("AFS_Logoff_Event - Preserving Tokens");
1144 DebugEvent0("AFS_Logoff_Event - End");
1147 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1149 TCHAR profileDir[1024] = TEXT("");
1151 PTOKEN_USER tokenUser = NULL;
1153 WCHAR szUserW[128] = L"";
1154 char szUserA[128] = "";
1155 char szClient[MAX_PATH];
1156 char szPath[MAX_PATH] = "";
1162 /* Make sure the AFS Libraries are initialized */
1165 DebugEvent0("AFS_Logon_Event - Start");
1167 DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1169 memset(&opt, 0, sizeof(LogonOptions_t));
1171 if (pInfo->UserName && pInfo->Domain) {
1172 char username[MAX_USERNAME_LENGTH] = "";
1173 char domain[MAX_DOMAIN_LENGTH] = "";
1176 DebugEvent0("AFS_Logon_Event - pInfo UserName and Domain");
1178 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1179 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1180 username, sizeof(username), NULL, NULL);
1182 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1183 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1184 domain, sizeof(domain), NULL, NULL);
1186 DebugEvent0("AFS_Logon_Event - Calling GetDomainLogonOptions");
1187 GetDomainLogonOptions(NULL, username, domain, &opt);
1189 if (!pInfo->UserName)
1190 DebugEvent0("AFS_Logon_Event - No pInfo->UserName");
1192 DebugEvent0("AFS_Logon_Event - No pInfo->Domain");
1195 DebugEvent("AFS_Logon_Event - opt.LogonOption = %lX opt.flags = %lX",
1196 opt.LogonOption, opt.flags);
1198 if (!ISLOGONINTEGRATED(opt.LogonOption) || !ISREMOTE(opt.flags)) {
1199 DebugEvent0("AFS_Logon_Event - Logon is not integrated or not remote");
1200 goto done_logon_event;
1203 DebugEvent0("AFS_Logon_Event - Calling GetTokenInformation");
1205 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1207 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1208 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1210 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1212 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1217 /* We can't use pInfo->Domain for the domain since in the cross realm case
1218 * this is source domain and not the destination domain.
1220 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1221 WCHAR Domain[64]=L"";
1222 GetLocalShortDomain(Domain, sizeof(Domain));
1223 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1224 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1225 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1229 if (strlen(profileDir)) {
1230 DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1232 DebugEvent0("AFS_Logon_Event - Unable to load profile");
1236 dwSize = sizeof(szUserA);
1237 if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1238 StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1239 WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1244 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1245 StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1247 DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1249 memset (&nr, 0x00, sizeof(NETRESOURCE));
1250 nr.dwType=RESOURCETYPE_DISK;
1252 nr.lpRemoteName=szPath;
1253 res = WNetAddConnection2(&nr,NULL,szUserA,0);
1255 DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1256 szPath, szUserA,res);
1258 DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1260 DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1263 LocalFree(tokenUser);
1265 DebugEvent0("AFS_Logon_Event - End");
1269 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1271 NTSTATUS Status = 0;
1272 TOKEN_STATISTICS Stats;
1278 *ppSessionData = NULL;
1280 Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1284 Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1285 if ( FAILED(Status) || !ppSessionData )
1291 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1293 WCHAR szUserW[128] = L"";
1294 char szUserA[128] = "";
1295 char szPath[MAX_PATH] = "";
1296 char szLogonId[128] = "";
1298 char filename[MAX_PATH] = "";
1299 char newfilename[MAX_PATH] = "";
1300 char commandline[MAX_PATH+256] = "";
1301 STARTUPINFO startupinfo;
1302 PROCESS_INFORMATION procinfo;
1303 HANDLE hf = INVALID_HANDLE_VALUE;
1305 LUID LogonId = {0, 0};
1306 PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1308 HKEY hKey1 = NULL, hKey2 = NULL;
1310 /* Make sure the KFW Libraries are initialized */
1313 DebugEvent0("KFW_Logon_Event - Start");
1315 GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1317 if ( pLogonSessionData ) {
1318 LogonId = pLogonSessionData->LogonId;
1319 DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1321 sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1322 LsaFreeReturnBuffer( pLogonSessionData );
1324 DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1328 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1329 if ( count > sizeof(filename) || count == 0 ) {
1330 GetWindowsDirectory(filename, sizeof(filename));
1333 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1334 if ( count > sizeof(filename) || count == 0 ) {
1335 GetWindowsDirectory(filename, sizeof(filename));
1338 if ( strlen(filename) + strlen(szLogonId) + 2 > sizeof(filename) ) {
1339 DebugEvent0("KFW_Logon_Event - filename too long");
1343 strcat(filename, "\\");
1344 strcat(filename, szLogonId);
1346 hf = CreateFile(filename, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING,
1347 FILE_ATTRIBUTE_NORMAL, NULL);
1348 if (hf == INVALID_HANDLE_VALUE) {
1349 DebugEvent0("KFW_Logon_Event - file cannot be opened");
1354 if (KFW_AFS_set_file_cache_dacl(filename, pInfo->hToken)) {
1355 DebugEvent0("KFW_Logon_Event - unable to set dacl");
1356 DeleteFile(filename);
1360 if (KFW_AFS_obtain_user_temp_directory(pInfo->hToken, newfilename, sizeof(newfilename))) {
1361 DebugEvent0("KFW_Logon_Event - unable to obtain temp directory");
1365 if ( strlen(newfilename) + strlen(szLogonId) + 2 > sizeof(newfilename) ) {
1366 DebugEvent0("KFW_Logon_Event - new filename too long");
1370 strcat(newfilename, "\\");
1371 strcat(newfilename, szLogonId);
1373 if (!MoveFileEx(filename, newfilename,
1374 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) {
1375 DebugEvent("KFW_Logon_Event - MoveFileEx failed GLE = 0x%x", GetLastError());
1379 sprintf(commandline, "afscpcc.exe \"%s\"", newfilename);
1381 GetStartupInfo(&startupinfo);
1382 if (CreateProcessAsUser( pInfo->hToken,
1388 CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1394 DebugEvent("KFW_Logon_Event - CommandLine %s", commandline);
1396 WaitForSingleObject(procinfo.hProcess, 30000);
1398 CloseHandle(procinfo.hThread);
1399 CloseHandle(procinfo.hProcess);
1401 DebugEvent0("KFW_Logon_Event - CreateProcessFailed");
1404 DeleteFile(filename);
1406 DebugEvent0("KFW_Logon_Event - End");