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 for [%s]", effDomain);
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 UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
754 UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
755 UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
757 /* Make sure AD-DOMANS sent from login that is sent to us is striped */
758 ctemp = strchr(uname, '@');
759 if (ctemp) *ctemp = 0;
761 /* is the name all lowercase? */
762 for ( ctemp = uname; *ctemp ; ctemp++) {
763 if ( !islower(*ctemp) ) {
764 lowercased_name = FALSE;
773 GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
774 retryInterval = opt.retryInterval;
775 sleepInterval = opt.sleepInterval;
776 *lpLogonScript = opt.logonScript;
778 if (retryInterval < sleepInterval)
779 sleepInterval = retryInterval;
781 DebugEvent("Got logon script: %S",opt.logonScript);
783 afsWillAutoStart = AFSWillAutoStart();
785 DebugEvent("LogonOption[%x], Service AutoStart[%d]",
786 opt.LogonOption,afsWillAutoStart);
788 /* Check for zero length password if integrated logon*/
789 if ( ISLOGONINTEGRATED(opt.LogonOption) ) {
790 if ( password[0] == 0 ) {
791 DebugEvent("Password is the empty string");
793 reason = "zero length password is illegal";
797 /* Get cell name if doing integrated logon.
798 We might overwrite this if we are logging into an AD realm and we find out that
799 the user's home dir is in some other cell. */
800 DebugEvent("About to call cm_GetRootCellName(%s)",cell);
801 code = cm_GetRootCellName(cell);
803 DebugEvent("Unable to obtain Root Cell");
805 reason = "unknown cell";
808 DebugEvent("Cell is %s",cell);
811 /* We get the user's home directory path, if applicable, though we can't lookup the
812 cell right away because the client service may not have started yet. This call
813 also sets the AD_REALM flag in opt.flags if applicable. */
814 if (ISREMOTE(opt.flags)) {
815 DebugEvent("Is Remote");
816 GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
820 /* loop until AFS is started. */
821 if (afsWillAutoStart) {
822 while (IsServiceRunning() || IsServiceStartPending()) {
823 DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
824 opt.LogonOption,afsWillAutoStart);
826 if (ISADREALM(opt.flags)) {
827 code = GetFileCellName(homePath,cell,256);
829 DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
831 /* Don't bail out if GetFileCellName failed.
832 * The home dir may not be in AFS after all.
837 /* if Integrated Logon */
838 if (ISLOGONINTEGRATED(opt.LogonOption))
840 if ( KFW_is_available() ) {
841 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
842 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
843 uname,opt.smbName,cell,code);
844 if (code == 0 && opt.theseCells) {
845 char * principal, *p;
848 StringCchLength(cell, MAX_DOMAIN_LENGTH, &tlen);
850 StringCchLength(uname, MAX_USERNAME_LENGTH, &tlen);
853 /* tlen is now the length of uname in characters */
854 principal = (char *)malloc(len * sizeof(char));
856 StringCchCopy(principal, len, uname);
857 p = principal + tlen;
859 StringCchCopy(p, len - tlen - 1, cell);
866 code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
867 DebugEvent("KFW_AFS_get_cred uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
868 principal,opt.smbName,p,code2);
875 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
876 uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
878 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2 Code[%x] uname[%s] smbname=[%s] Cell[%s] PwExp=[%d] Reason=[%s]",
879 code,uname,opt.smbName,cell,pw_exp,reason?reason:"");
881 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
882 for ( ctemp = uname; *ctemp ; ctemp++) {
883 *ctemp = tolower(*ctemp);
885 lowercased_name = TRUE;
889 /* is service started yet?*/
891 /* If we've failed because the client isn't running yet and the
892 * client is set to autostart (and therefore it makes sense for
893 * us to wait for it to start) then sleep a while and try again.
894 * If the error was something else, then give up. */
895 if (code != KTC_NOCM && code != KTC_NOCMRPC)
899 /*JUST check to see if its running*/
900 if (IsServiceRunning())
902 if (!IsServiceStartPending()) {
904 reason = "AFS Service start failed";
909 /* If the retry interval has expired and we still aren't
910 * logged in, then just give up if we are not in interactive
911 * mode or the failSilently flag is set, otherwise let the
912 * user know we failed and give them a chance to try again. */
913 if (retryInterval <= 0) {
914 reason = "AFS not running";
915 if (!interactive || opt.failSilently)
917 flag = MessageBox(hwndOwner,
918 "AFS is still starting. Retry?",
920 MB_ICONQUESTION | MB_RETRYCANCEL);
921 if (flag == IDCANCEL)
924 /* Wait just a little while and try again */
925 retryInterval = opt.retryInterval;
929 Sleep(sleepInterval * 1000);
930 retryInterval -= sleepInterval;
933 DebugEvent("while loop exited");
934 /* remove any kerberos 5 tickets currently held by the SYSTEM account
937 if (ISLOGONINTEGRATED(opt.LogonOption) && KFW_is_available()) {
938 sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
939 KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
941 KFW_AFS_destroy_tickets_for_principal(uname);
949 StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
951 if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
952 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
954 h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
956 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
958 DeregisterEventSource(h);
960 code = MapAuthError(code);
963 if (ISLOGONINTEGRATED(opt.LogonOption) && (code!=0))
966 LocalFree(*lpLogonScript);
967 *lpLogonScript = NULL;
968 if (!afsWillAutoStart) // its not running, so if not autostart or integrated logon then just skip
973 if (opt.theseCells) free(opt.theseCells);
974 if (opt.smbName) free(opt.smbName);
976 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
980 DWORD APIENTRY NPPasswordChangeNotify(
981 LPCWSTR lpAuthentInfoType,
982 LPVOID lpAuthentInfo,
983 LPCWSTR lpPreviousAuthentInfoType,
984 LPVOID lpPreviousAuthentInfo,
985 LPWSTR lpStationName,
986 LPVOID StationHandle,
989 /* Make sure the AFS Libraries are initialized */
992 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
998 #include <afs/vice.h>
999 #include <afs/fs_utils.h>
1001 BOOL IsPathInAfs(const CHAR *strPath)
1004 struct ViceIoctl blob;
1008 blob.out_size = 2048;
1011 code = pioctl((LPTSTR)((LPCTSTR)strPath), VIOC_FILE_CELL_NAME, &blob, 1);
1018 typedef struct _WLX_NOTIFICATION_INFO {
1023 PWSTR WindowStation;
1026 PFNMSGECALLBACK pStatusCallback;
1027 } WLX_NOTIFICATION_INFO, *PWLX_NOTIFICATION_INFO;
1030 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
1032 DWORD LSPtype, LSPsize;
1035 /* Make sure the AFS Libraries are initialized */
1038 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1039 0, KEY_QUERY_VALUE, &NPKey);
1040 LSPsize=sizeof(TraceOption);
1041 RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
1042 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
1044 RegCloseKey (NPKey);
1045 DebugEvent0("AFS_Startup_Event");
1048 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
1051 TCHAR profileDir[1024] = TEXT("");
1053 PTOKEN_USER tokenUser = NULL;
1055 DWORD LSPtype, LSPsize;
1057 DWORD LogoffPreserveTokens = 0;
1060 /* Make sure the AFS Libraries are initialized */
1063 DebugEvent0("AFS_Logoff_Event - Start");
1065 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
1066 0, KEY_QUERY_VALUE, &NPKey);
1067 LSPsize=sizeof(LogoffPreserveTokens);
1068 RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
1069 &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
1070 RegCloseKey (NPKey);
1072 if (!LogoffPreserveTokens) {
1073 memset(&opt, 0, sizeof(LogonOptions_t));
1075 if (pInfo->UserName && pInfo->Domain) {
1076 char username[MAX_USERNAME_LENGTH] = "";
1077 char domain[MAX_DOMAIN_LENGTH] = "";
1080 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1081 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1082 username, sizeof(username), NULL, NULL);
1084 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1085 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1086 domain, sizeof(domain), NULL, NULL);
1088 GetDomainLogonOptions(NULL, username, domain, &opt);
1091 if (ISREMOTE(opt.flags)) {
1092 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1094 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1095 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1097 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1099 DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1104 /* We can't use pInfo->Domain for the domain since in the cross realm case
1105 * this is source domain and not the destination domain.
1107 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1108 WCHAR Domain[64]=L"";
1109 GetLocalShortDomain(Domain, sizeof(Domain));
1110 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1111 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1112 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1116 if (strlen(profileDir)) {
1117 DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
1118 if (!IsPathInAfs(profileDir)) {
1119 if (code = ktc_ForgetAllTokens())
1120 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1122 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1124 DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
1127 DebugEvent0("AFS_Logoff_Event - Unable to load profile");
1131 LocalFree(tokenUser);
1133 DebugEvent0("AFS_Logoff_Event - Local Logon");
1134 if (code = ktc_ForgetAllTokens())
1135 DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
1137 DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
1140 DebugEvent0("AFS_Logoff_Event - Preserving Tokens");
1143 DebugEvent0("AFS_Logoff_Event - End");
1146 VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1148 TCHAR profileDir[1024] = TEXT("");
1150 PTOKEN_USER tokenUser = NULL;
1152 WCHAR szUserW[128] = L"";
1153 char szUserA[128] = "";
1154 char szClient[MAX_PATH];
1155 char szPath[MAX_PATH] = "";
1161 /* Make sure the AFS Libraries are initialized */
1164 DebugEvent0("AFS_Logon_Event - Start");
1166 DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
1168 memset(&opt, 0, sizeof(LogonOptions_t));
1170 if (pInfo->UserName && pInfo->Domain) {
1171 char username[MAX_USERNAME_LENGTH] = "";
1172 char domain[MAX_DOMAIN_LENGTH] = "";
1175 DebugEvent0("AFS_Logon_Event - pInfo UserName and Domain");
1177 StringCchLengthW(pInfo->UserName, MAX_USERNAME_LENGTH, &szlen);
1178 WideCharToMultiByte(CP_UTF8, 0, pInfo->UserName, szlen,
1179 username, sizeof(username), NULL, NULL);
1181 StringCchLengthW(pInfo->Domain, MAX_DOMAIN_LENGTH, &szlen);
1182 WideCharToMultiByte(CP_UTF8, 0, pInfo->Domain, szlen,
1183 domain, sizeof(domain), NULL, NULL);
1185 DebugEvent0("AFS_Logon_Event - Calling GetDomainLogonOptions");
1186 GetDomainLogonOptions(NULL, username, domain, &opt);
1188 if (!pInfo->UserName)
1189 DebugEvent0("AFS_Logon_Event - No pInfo->UserName");
1191 DebugEvent0("AFS_Logon_Event - No pInfo->Domain");
1194 DebugEvent("AFS_Logon_Event - opt.LogonOption = %lX opt.flags = %lX",
1195 opt.LogonOption, opt.flags);
1197 if (!ISLOGONINTEGRATED(opt.LogonOption) || !ISREMOTE(opt.flags)) {
1198 DebugEvent0("AFS_Logon_Event - Logon is not integrated or not remote");
1199 goto done_logon_event;
1202 DebugEvent0("AFS_Logon_Event - Calling GetTokenInformation");
1204 if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
1206 if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
1207 tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
1209 if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
1211 DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
1216 /* We can't use pInfo->Domain for the domain since in the cross realm case
1217 * this is source domain and not the destination domain.
1219 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
1220 WCHAR Domain[64]=L"";
1221 GetLocalShortDomain(Domain, sizeof(Domain));
1222 if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
1223 if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
1224 GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
1228 if (strlen(profileDir)) {
1229 DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
1231 DebugEvent0("AFS_Logon_Event - Unable to load profile");
1235 dwSize = sizeof(szUserA);
1236 if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
1237 StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
1238 WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
1243 lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
1244 StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
1246 DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
1248 memset (&nr, 0x00, sizeof(NETRESOURCE));
1249 nr.dwType=RESOURCETYPE_DISK;
1251 nr.lpRemoteName=szPath;
1252 res = WNetAddConnection2(&nr,NULL,szUserA,0);
1254 DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
1255 szPath, szUserA,res);
1257 DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
1259 DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
1262 LocalFree(tokenUser);
1264 DebugEvent0("AFS_Logon_Event - End");
1268 GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
1270 NTSTATUS Status = 0;
1271 TOKEN_STATISTICS Stats;
1277 *ppSessionData = NULL;
1279 Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
1283 Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
1284 if ( FAILED(Status) || !ppSessionData )
1290 VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
1292 WCHAR szUserW[128] = L"";
1293 char szUserA[128] = "";
1294 char szPath[MAX_PATH] = "";
1295 char szLogonId[128] = "";
1298 char commandline[512];
1299 STARTUPINFO startupinfo;
1300 PROCESS_INFORMATION procinfo;
1302 LUID LogonId = {0, 0};
1303 PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
1305 HKEY hKey1 = NULL, hKey2 = NULL;
1307 /* Make sure the KFW Libraries are initialized */
1310 DebugEvent0("KFW_Logon_Event - Start");
1312 GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
1314 if ( pLogonSessionData ) {
1315 LogonId = pLogonSessionData->LogonId;
1316 DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
1318 sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
1319 LsaFreeReturnBuffer( pLogonSessionData );
1321 DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
1325 count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
1326 if ( count > sizeof(filename) || count == 0 ) {
1327 GetWindowsDirectory(filename, sizeof(filename));
1330 if ( strlen(filename) + strlen(szLogonId) + 2 <= sizeof(filename) ) {
1331 strcat(filename, "\\");
1332 strcat(filename, szLogonId);
1334 sprintf(commandline, "afscpcc.exe \"%s\"", filename);
1336 GetStartupInfo(&startupinfo);
1337 if (CreateProcessAsUser( pInfo->hToken,
1343 CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
1349 WaitForSingleObject(procinfo.hProcess, 30000);
1351 CloseHandle(procinfo.hThread);
1352 CloseHandle(procinfo.hProcess);
1356 DeleteFile(filename);
1358 DebugEvent0("KFW_Logon_Event - End");