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
10 #include <afs/param.h>
17 #include <afs/pioctl_nt.h>
18 #include <afs/kautils.h>
19 #include "cm_config.h"
24 #include <sys/types.h>
27 DWORD LogonOption,TraceOption;
33 #define REG_CLIENT_PARMS_KEY "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters"
34 #define REG_CLIENT_PROVIDER_KEY "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\NetworkProvider"
35 #define REG_CLIENT_RETRY_INTERVAL_PARM "LoginRetryInterval"
36 #define REG_CLIENT_FAIL_SILENTLY_PARM "FailLoginsSilently"
37 #define DEFAULT_RETRY_INTERVAL 30 /* seconds*/
38 #define DEFAULT_FAIL_SILENTLY FALSE
39 #define DEFAULT_SLEEP_INTERVAL 5 /* seconds*/
41 #define ISLOGONINTEGRATED(v) ( ((v) & LOGON_OPTION_INTEGRATED)==LOGON_OPTION_INTEGRATED)
42 #define ISHIGHSECURITY(v) ( ((v) & LOGON_OPTION_HIGHSECURITY)==LOGON_OPTION_HIGHSECURITY)
44 #define TRACE_OPTION_EVENT 1
45 #define ISLOGONTRACE(v) ( ((v) & TRACE_OPTION_EVENT)==TRACE_OPTION_EVENT)
48 /* Structure def copied from DDK (NTDEF.H) */
49 typedef struct UNICODE_STRING {
50 USHORT Length; /* number of bytes of Buffer actually used */
51 USHORT MaximumLength; /* sizeof buffer in bytes */
52 WCHAR *Buffer; /* 16 bit characters */
55 /* Structure def copied from NP API documentation */
56 typedef struct _MSV1_0_INTERACTIVE_LOGON {
57 DWORD MessageType; /* Actually this is an enum; ignored */
58 UNICODE_STRING LogonDomainName;
59 UNICODE_STRING UserName;
60 UNICODE_STRING Password;
61 } MSV1_0_INTERACTIVE_LOGON;
67 * We get a logon script pathname from the HKEY_LOCAL_MACHINE registry.
68 * I don't know what good this does; I just copied it from DFS.
70 * Returns NULL on failure.
74 void DebugEvent0(char *a)
76 HANDLE h; char *ptbuf[1];
77 if (!ISLOGONTRACE(TraceOption))
79 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
81 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
82 DeregisterEventSource(h);
86 void DebugEvent(char *a,char *b,...)
88 HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
90 if (!ISLOGONTRACE(TraceOption))
92 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
94 _vsnprintf(buf,MAXBUF_,b,marker);
97 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);\
98 DeregisterEventSource(h);
102 CHAR *GenRandomName(CHAR *pbuf)
105 srand( (unsigned)time( NULL ) );
106 for (i=0;i<MAXRANDOMNAMELEN-1;i++)
107 pbuf[i]='a'+(rand() % 26);
108 pbuf[MAXRANDOMNAMELEN-1]=0;
112 WCHAR *GetLogonScript(CHAR *pname)
116 DWORD LSPtype, LSPsize;
118 WCHAR randomName[MAXRANDOMNAMELEN];
121 * Get Network Provider key.
122 * Assume this works or we wouldn't be here.
124 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PROVIDER_KEY,
125 0, KEY_QUERY_VALUE, &NPKey);
128 * Get Logon Script pathname length
131 code = RegQueryValueExW(NPKey, L"LogonScript", NULL,
132 &LSPtype, NULL, &LSPsize);
139 if (LSPtype != REG_SZ) { /* Maybe handle REG_EXPAND_SZ? */
144 buf=(WCHAR *)LocalAlloc(LMEM_FIXED,LSPsize);
145 script=(WCHAR *)LocalAlloc(LMEM_FIXED,LSPsize+(MAXRANDOMNAMELEN)*sizeof(WCHAR));
147 * Explicitly call UNICODE version
148 * Assume it will succeed since it did before
150 (void) RegQueryValueExW(NPKey, L"LogonScript", NULL,
151 &LSPtype, (LPBYTE)buf, &LSPsize);
152 MultiByteToWideChar(CP_ACP,0,pname,strlen(pname)+1,randomName,(strlen(pname)+1)*sizeof(WCHAR));
153 swprintf(script,buf,randomName);
158 HANDLE h; char *ptbuf[1],buf[132],tbuf[255];
159 WideCharToMultiByte(CP_ACP,0,script,LSPsize,tbuf,255,NULL,NULL);
160 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
161 sprintf(buf, "Script[%s,%d] Return Code[%x]",tbuf,LSPsize,code);
163 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
164 DeregisterEventSource(h);
172 BOOLEAN AFSWillAutoStart(void)
177 BOOLEAN result = FALSE;
178 LPQUERY_SERVICE_CONFIG pConfig = NULL;
182 /* Open services manager */
183 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
184 if (!scm) return FALSE;
186 /* Open AFSD service */
187 svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
191 /* Query AFSD service config, first just to get buffer size */
192 /* Expected to fail, so don't test return value */
193 (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
194 status = GetLastError();
195 if (status != ERROR_INSUFFICIENT_BUFFER)
198 /* Allocate buffer */
199 pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
203 /* Query AFSD service config, this time for real */
204 flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
208 /* Is it autostart? */
209 if (pConfig->dwStartType < SERVICE_DEMAND_START)
215 CloseServiceHandle(svc);
217 CloseServiceHandle(scm);
222 DWORD MapAuthError(DWORD code)
227 return WN_NO_NETWORK;
228 /* case INTK_BADPW: return WN_BAD_PASSWORD;*/
229 /* case KERB_ERR_PRINCIPAL_UNKNOWN: return WN_BAD_USER;*/
230 default: return WN_SUCCESS;
234 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
238 case DLL_PROCESS_ATTACH:
239 /* Initialize AFS libraries */
245 /* Everything else succeeds but does nothing. */
246 case DLL_PROCESS_DETACH:
247 case DLL_THREAD_ATTACH:
248 case DLL_THREAD_DETACH:
256 DWORD APIENTRY NPGetCaps(DWORD index)
260 /* Don't have our own type; use somebody else's. */
261 return WNNC_NET_SUN_PC_NFS;
267 static void GetLoginBehavior(int *pRetryInterval, BOOLEAN *pFailSilently)
273 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY, 0, KEY_QUERY_VALUE, &hKey);
274 if (result != ERROR_SUCCESS) {
275 *pRetryInterval = DEFAULT_RETRY_INTERVAL;
276 *pFailSilently = DEFAULT_FAIL_SILENTLY;
280 result = RegQueryValueEx(hKey, REG_CLIENT_RETRY_INTERVAL_PARM, 0, 0, (BYTE *)pRetryInterval, &dummyLen);
281 if (result != ERROR_SUCCESS)
282 *pRetryInterval = DEFAULT_RETRY_INTERVAL;
284 result = RegQueryValueEx(hKey, REG_CLIENT_FAIL_SILENTLY_PARM, 0, 0, (BYTE *)pFailSilently, &dummyLen);
285 if (result != ERROR_SUCCESS)
286 *pFailSilently = DEFAULT_FAIL_SILENTLY;
288 /* Make sure this is really a bool value in the strict sense*/
289 *pFailSilently = !!*pFailSilently;
294 BOOL IsServiceRunning (void)
296 SERVICE_STATUS Status;
298 memset (&Status, 0x00, sizeof(Status));
299 Status.dwCurrentState = SERVICE_STOPPED;
301 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
304 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
306 QueryServiceStatus (hService, &Status);
307 CloseServiceHandle (hService);
310 CloseServiceHandle (hManager);
312 DebugEvent("AFS AfsLogon - Test Service Running","Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
313 return (Status.dwCurrentState == SERVICE_RUNNING);
319 UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOutStringLen)
323 GetCPInfo(CP_ACP, &CodePageInfo);
325 if (CodePageInfo.MaxCharSize > 1)
326 // Only supporting non-Unicode strings
329 if (((LPBYTE) uInputString.Buffer)[1] == '\0')
331 // Looks like unicode, better translate it
332 // UNICODE_STRING specifies the length of the buffer string in Bytes not WCHARS
333 WideCharToMultiByte(CP_ACP, 0, (LPCWSTR) uInputString.Buffer, uInputString.Length/2,
334 lpszOutputString, nOutStringLen-1, NULL, NULL);
335 lpszOutputString[max(uInputString.Length/2,nOutStringLen-1)] = '\0';
339 } // UnicodeStringToANSI
341 DWORD APIENTRY NPLogonNotify(
343 LPCWSTR lpAuthentInfoType,
344 LPVOID lpAuthentInfo,
345 LPCWSTR lpPreviousAuthentInfoType,
346 LPVOID lpPreviousAuthentInfo,
347 LPWSTR lpStationName,
348 LPVOID StationHandle,
349 LPWSTR *lpLogonScript)
353 char password[256]="";
354 char cell[256]="<non-integrated logon>";
355 MSV1_0_INTERACTIVE_LOGON *IL;
361 DWORD LSPtype, LSPsize;
363 HWND hwndOwner = (HWND)StationHandle;
364 BOOLEAN failSilently;
366 int sleepInterval = DEFAULT_SLEEP_INTERVAL; /* seconds */
367 BOOLEAN afsWillAutoStart;
368 CHAR RandomName[MAXRANDOMNAMELEN];
369 BOOLEAN uppercased_name = TRUE;
371 /* Initialize Logon Script to none */
374 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
376 /* Are we interactive? */
377 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
379 /* Convert from Unicode to ANSI */
380 UnicodeStringToANSI(IL->UserName, uname, 256);
381 UnicodeStringToANSI(IL->Password, password, 256);
383 /* Make sure AD-DOMANS sent from login that is sent to us is striped */
384 ctemp = strchr(uname, '@');
385 if (ctemp) *ctemp = 0;
387 /* is the name all uppercase? */
388 for ( ctemp = uname; *ctemp ; ctemp++) {
389 if ( islower(*ctemp) ) {
390 uppercased_name = FALSE;
395 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
396 0, KEY_QUERY_VALUE, &NPKey);
397 LSPsize=sizeof(TraceOption);
398 RegQueryValueEx(NPKey, "TraceOption", NULL,
399 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
406 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PROVIDER_KEY,
407 0, KEY_QUERY_VALUE, &NPKey);
409 LSPsize=sizeof(LogonOption);
410 code = RegQueryValueEx(NPKey, "LogonOptions", NULL,
411 &LSPtype, (LPBYTE)&LogonOption, &LSPsize);
414 if ((code!=0) || (LSPtype!=REG_DWORD))
415 LogonOption=LOGON_OPTION_INTEGRATED; /*default to integrated logon only*/
417 afsWillAutoStart = AFSWillAutoStart();
419 DebugEvent("AFS AfsLogon - NPLogonNotify","LogonOption[%x], Service AutoStart[%d]",
420 LogonOption,afsWillAutoStart);
422 /* Get local machine specified login behavior (or defaults) */
423 GetLoginBehavior(&retryInterval, &failSilently);
425 /* Check for zero length password if integrated logon*/
426 if ( ISLOGONINTEGRATED(LogonOption) ) {
427 if ( password[0] == 0 ) {
429 reason = "zero length password is illegal";
433 /* Get cell name if doing integrated logon */
434 code = cm_GetRootCellName(cell);
437 reason = "unknown cell";
441 /*only do if high security option is on*/
442 if (ISHIGHSECURITY(LogonOption))
443 *lpLogonScript = GetLogonScript(GenRandomName(RandomName));
446 /* loop until AFS is started. */
450 /* is service started yet?*/
451 DebugEvent("AFS AfsLogon - ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s]",
454 /* if Integrated Logon only */
455 if (ISLOGONINTEGRATED(LogonOption) && !ISHIGHSECURITY(LogonOption))
457 if ( KFW_is_available() )
458 code = KFW_AFS_get_cred(uname, cell, password, 0, uname, &reason);
460 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
461 uname, "", cell, password, uname, 0, &pw_exp, 0,
463 DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2","Code[%x]",
465 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && uppercased_name ) {
466 for ( ctemp = uname; *ctemp ; ctemp++) {
467 *ctemp = tolower(*ctemp);
469 uppercased_name = FALSE;
473 /* if Integrated Logon and High Security pass random generated name*/
474 else if (ISLOGONINTEGRATED(LogonOption) && ISHIGHSECURITY(LogonOption))
476 if ( KFW_is_available() )
477 code = KFW_AFS_get_cred(uname, cell, password, 0, RandomName, &reason);
479 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
480 uname, "", cell, password,RandomName, 0, &pw_exp, 0,
482 DebugEvent("AFS AfsLogon - (Both)ka_UserAuthenticateGeneral2","Code[%x] RandomName[%s]",
485 if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && uppercased_name ) {
486 for ( ctemp = uname; *ctemp ; ctemp++) {
487 *ctemp = tolower(*ctemp);
489 uppercased_name = FALSE;
493 /*JUST check to see if its running*/
494 if (IsServiceRunning())
497 if (!afsWillAutoStart)
501 /* If we've failed because the client isn't running yet and the
502 * client is set to autostart (and therefore it makes sense for
503 * us to wait for it to start) then sleep a while and try again.
504 * If the error was something else, then give up. */
505 if (code != KTC_NOCM && code != KTC_NOCMRPC || !afsWillAutoStart)
508 /* If the retry interval has expired and we still aren't
509 * logged in, then just give up if we are not in interactive
510 * mode or the failSilently flag is set, otherwise let the
511 * user know we failed and give them a chance to try again. */
512 if (retryInterval <= 0) {
513 reason = "AFS not running";
514 if (!interactive || failSilently)
516 flag = MessageBox(hwndOwner,
517 "AFS is still starting. Retry?",
519 MB_ICONQUESTION | MB_RETRYCANCEL);
520 if (flag == IDCANCEL)
523 /* Wait just a little while and try again */
524 retryInterval = sleepInterval = DEFAULT_SLEEP_INTERVAL;
527 if (retryInterval < sleepInterval)
528 sleepInterval = retryInterval;
530 Sleep(sleepInterval * 1000);
532 retryInterval -= sleepInterval;
535 /* remove any kerberos 5 tickets currently held by the SYSTEM account */
536 if ( KFW_is_available() )
537 KFW_AFS_destroy_tickets_for_cell(cell);
541 sprintf(msg, "Integrated login failed: %s", reason);
543 if (interactive && !failSilently)
544 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
549 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
551 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
553 DeregisterEventSource(h);
555 code = MapAuthError(code);
558 if (ISLOGONINTEGRATED(LogonOption) && (code!=0))
561 LocalFree(*lpLogonScript);
562 *lpLogonScript = NULL;
563 if (!afsWillAutoStart) // its not running, so if not autostart or integrated logon then just skip
569 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
573 DWORD APIENTRY NPPasswordChangeNotify(
574 LPCWSTR lpAuthentInfoType,
575 LPVOID lpAuthentInfo,
576 LPCWSTR lpPreviousAuthentInfoType,
577 LPVOID lpPreviousAuthentInfo,
578 LPWSTR lpStationName,
579 LPVOID StationHandle,
582 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");