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)
47 /* Structure def copied from DDK (NTDEF.H) */
48 typedef struct UNICODE_STRING {
49 USHORT Length; /* number of bytes of Buffer actually used */
50 USHORT MaximumLength; /* sizeof buffer in bytes */
51 WCHAR *Buffer; /* 16 bit characters */
54 /* Structure def copied from NP API documentation */
55 typedef struct _MSV1_0_INTERACTIVE_LOGON {
56 DWORD MessageType; /* Actually this is an enum; ignored */
57 UNICODE_STRING LogonDomainName;
58 UNICODE_STRING UserName;
59 UNICODE_STRING Password;
60 } MSV1_0_INTERACTIVE_LOGON;
65 * We get a logon script pathname from the HKEY_LOCAL_MACHINE registry.
66 * I don't know what good this does; I just copied it from DFS.
68 * Returns NULL on failure.
72 void DebugEvent0(char *a)
74 HANDLE h; char *ptbuf[1];
75 if (!ISLOGONTRACE(TraceOption))
77 h = RegisterEventSource(NULL, a);
79 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
80 DeregisterEventSource(h);
84 void DebugEvent(char *a,char *b,...)
86 HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
88 if (!ISLOGONTRACE(TraceOption))
90 h = RegisterEventSource(NULL, a);
92 _vsnprintf(buf,MAXBUF_,b,marker);
94 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);\
95 DeregisterEventSource(h);
99 CHAR *GenRandomName(CHAR *pbuf)
102 srand( (unsigned)time( NULL ) );
103 for (i=0;i<MAXRANDOMNAMELEN-1;i++)
104 pbuf[i]='a'+(rand() % 26);
105 pbuf[MAXRANDOMNAMELEN-1]=0;
109 WCHAR *GetLogonScript(CHAR *pname)
113 DWORD LSPtype, LSPsize;
115 WCHAR randomName[MAXRANDOMNAMELEN];
118 * Get Network Provider key.
119 * Assume this works or we wouldn't be here.
121 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PROVIDER_KEY,
122 0, KEY_QUERY_VALUE, &NPKey);
125 * Get Logon Script pathname length
128 code = RegQueryValueExW(NPKey, L"LogonScript", NULL,
129 &LSPtype, NULL, &LSPsize);
136 if (LSPtype != REG_SZ) { /* Maybe handle REG_EXPAND_SZ? */
141 buf=(WCHAR *)LocalAlloc(LMEM_FIXED, LSPsize);
142 script=(WCHAR *)LocalAlloc(LMEM_FIXED,LSPsize+(MAXRANDOMNAMELEN)*sizeof(WCHAR));
144 * Explicitly call UNICODE version
145 * Assume it will succeed since it did before
147 (void) RegQueryValueExW(NPKey, L"LogonScript", NULL,
148 &LSPtype, (LPBYTE)buf, &LSPsize);
149 MultiByteToWideChar(CP_ACP,0,pname,strlen(pname)+1,randomName,(strlen(pname)+1)*sizeof(WCHAR));
150 swprintf(script,buf,randomName);
155 HANDLE h; char *ptbuf[1],buf[132],tbuf[255];
156 WideCharToMultiByte(CP_ACP,0,script,LSPsize,tbuf,255,NULL,NULL);
157 h = RegisterEventSource(NULL, "AFS AfsLogon - GetLogonScript");
158 sprintf(buf, "Script[%s,%d] Return Code[%x]",tbuf,LSPsize,code);
160 ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
161 DeregisterEventSource(h);
169 BOOLEAN AFSWillAutoStart(void)
174 BOOLEAN result = FALSE;
175 LPQUERY_SERVICE_CONFIG pConfig = NULL;
179 /* Open services manager */
180 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
181 if (!scm) return FALSE;
183 /* Open AFSD service */
184 svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
188 /* Query AFSD service config, first just to get buffer size */
189 /* Expected to fail, so don't test return value */
190 (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
191 status = GetLastError();
192 if (status != ERROR_INSUFFICIENT_BUFFER)
195 /* Allocate buffer */
196 pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED, BufSize);
200 /* Query AFSD service config, this time for real */
201 flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
205 /* Is it autostart? */
206 if (pConfig->dwStartType < SERVICE_DEMAND_START)
212 CloseServiceHandle(svc);
214 CloseServiceHandle(scm);
219 DWORD MapAuthError(DWORD code)
224 return WN_NO_NETWORK;
225 /* case INTK_BADPW: return WN_BAD_PASSWORD;*/
226 /* case KERB_ERR_PRINCIPAL_UNKNOWN: return WN_BAD_USER;*/
227 default: return WN_SUCCESS;
231 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
235 case DLL_PROCESS_ATTACH:
236 /* Initialize AFS libraries */
241 /* Everything else succeeds but does nothing. */
242 case DLL_PROCESS_DETACH:
243 case DLL_THREAD_ATTACH:
244 case DLL_THREAD_DETACH:
252 DWORD APIENTRY NPGetCaps(DWORD index)
256 /* Don't have our own type; use somebody else's. */
257 return WNNC_NET_SUN_PC_NFS;
263 static void GetLoginBehavior(int *pRetryInterval, BOOLEAN *pFailSilently)
269 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY, 0, KEY_QUERY_VALUE, &hKey);
270 if (result != ERROR_SUCCESS) {
271 *pRetryInterval = DEFAULT_RETRY_INTERVAL;
272 *pFailSilently = DEFAULT_FAIL_SILENTLY;
276 result = RegQueryValueEx(hKey, REG_CLIENT_RETRY_INTERVAL_PARM, 0, 0, (BYTE *)pRetryInterval, &dummyLen);
277 if (result != ERROR_SUCCESS)
278 *pRetryInterval = DEFAULT_RETRY_INTERVAL;
280 result = RegQueryValueEx(hKey, REG_CLIENT_FAIL_SILENTLY_PARM, 0, 0, (BYTE *)pFailSilently, &dummyLen);
281 if (result != ERROR_SUCCESS)
282 *pFailSilently = DEFAULT_FAIL_SILENTLY;
284 /* Make sure this is really a bool value in the strict sense*/
285 *pFailSilently = !!*pFailSilently;
290 BOOL IsServiceRunning (void)
292 SERVICE_STATUS Status;
294 memset (&Status, 0x00, sizeof(Status));
295 Status.dwCurrentState = SERVICE_STOPPED;
297 if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
300 if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
302 QueryServiceStatus (hService, &Status);
303 CloseServiceHandle (hService);
306 CloseServiceHandle (hManager);
308 DebugEvent("AFS AfsLogon - Test Service Running","Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
309 return (Status.dwCurrentState == SERVICE_RUNNING);
312 DWORD APIENTRY NPLogonNotify(
314 LPCWSTR lpAuthentInfoType,
315 LPVOID lpAuthentInfo,
316 LPCWSTR lpPreviousAuthentInfoType,
317 LPVOID lpPreviousAuthentInfo,
318 LPWSTR lpStationName,
319 LPVOID StationHandle,
320 LPWSTR *lpLogonScript)
325 MSV1_0_INTERACTIVE_LOGON *IL;
331 DWORD LSPtype, LSPsize;
333 HWND hwndOwner = (HWND)StationHandle;
334 BOOLEAN failSilently;
336 int sleepInterval = DEFAULT_SLEEP_INTERVAL; /* seconds */
337 BOOLEAN afsWillAutoStart;
338 CHAR RandomName[MAXRANDOMNAMELEN];
341 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
343 /* Are we interactive? */
344 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
346 /* Convert from Unicode to ANSI */
347 wcstombs(uname, IL->UserName.Buffer, 256);
348 wcstombs(password, IL->Password.Buffer, 256);
350 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
351 0, KEY_QUERY_VALUE, &NPKey);
352 LSPsize=sizeof(TraceOption);
353 RegQueryValueEx(NPKey, "TraceOption", NULL,
354 &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
361 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PROVIDER_KEY,
362 0, KEY_QUERY_VALUE, &NPKey);
364 LSPsize=sizeof(LogonOption);
365 code = RegQueryValueEx(NPKey, "LogonOptions", NULL,
366 &LSPtype, (LPBYTE)&LogonOption, &LSPsize);
369 if ((code!=0) || (LSPtype!=REG_DWORD))
370 LogonOption=LOGON_OPTION_INTEGRATED; /*default to integrated logon only*/
371 DebugEvent("AFS AfsLogon - NPLogonNotify","LogonOption[%x], Service AutoStart[%d]",LogonOption,AFSWillAutoStart());
372 /* Check for zero length password if integrated logon*/
373 if ( ISLOGONINTEGRATED(LogonOption) && (password[0] == 0) ) {
375 reason = "zero length password is illegal";
376 if (!ISHIGHSECURITY(LogonOption))
377 goto checkauth; /*skip the rest if integrated logon and not high security*/
381 /* Get cell name if doing integrated logon */
382 if (ISLOGONINTEGRATED(LogonOption))
384 code = cm_GetRootCellName(cell);
387 reason = "unknown cell";
388 if (!ISHIGHSECURITY(LogonOption))
389 goto checkauth; /*skip the rest if integrated logon and not high security*/
394 /* Get user specified login behavior (or defaults) */
395 GetLoginBehavior(&retryInterval, &failSilently);
397 afsWillAutoStart = AFSWillAutoStart();
399 if ( ISHIGHSECURITY(LogonOption))
400 *lpLogonScript = GetLogonScript(GenRandomName(RandomName)); /*only do if high security option is on*/
403 /* Possibly loop until AFS is started. */
404 while ( (ISHIGHSECURITY(LogonOption) || ISLOGONINTEGRATED(LogonOption))) {
407 /* is service started yet?*/
409 if (ISHIGHSECURITY(LogonOption) && !ISLOGONINTEGRATED(LogonOption)) /* if high security only then check for service started only*/
411 if (IsServiceRunning())
414 if (!afsWillAutoStart)
416 } else if (ISLOGONINTEGRATED(LogonOption) && !ISHIGHSECURITY(LogonOption)) /* if Integrated Logon only */
418 DebugEvent("AFS AfsLogon - ka_UserAuthenticateGeneral2","Code[%x],uame[%s] Cell[%s]",code,uname,cell);
419 code = ka_UserAuthenticateGeneral2(
420 KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
421 uname, "", cell, password,uname, 0, &pw_exp, 0,
423 DebugEvent("AFS AfsLogon - (INTEGERTED only)ka_UserAuthenticateGeneral2","Code[%x]",code);
424 } else if (ISLOGONINTEGRATED(LogonOption) && ISHIGHSECURITY(LogonOption)) /* if Integrated Logon and High Security pass random generated name*/
426 code = ka_UserAuthenticateGeneral2(
427 KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
428 uname, "", cell, password,RandomName, 0, &pw_exp, 0,
430 DebugEvent("AFS AfsLogon - (Both)ka_UserAuthenticateGeneral2","Code[%x],RandomName[%s]",code,RandomName);
432 code = KTC_NOCM; /* we shouldn't ever get here*/
435 /* If we've failed because the client isn't running yet and the
436 * client is set to autostart (and therefore it makes sense for
437 * us to wait for it to start) then sleep a while and try again.
438 * If the error was something else, then give up. */
439 if (code != KTC_NOCM && code != KTC_NOCMRPC || !afsWillAutoStart)
442 /* If the retry interval has expired and we still aren't
443 * logged in, then just give up if we are not in interactive
444 * mode or the failSilently flag is set, otherwise let the
445 * user know we failed and give them a chance to try again. */
446 if (retryInterval <= 0) {
447 if (!interactive || failSilently)
449 flag = MessageBox(hwndOwner,
450 "AFS is still starting. Retry?",
452 MB_ICONQUESTION | MB_RETRYCANCEL);
453 if (flag == IDCANCEL)
456 /* Wait just a little while and try again */
457 retryInterval = sleepInterval = DEFAULT_SLEEP_INTERVAL;
460 if (retryInterval < sleepInterval)
461 sleepInterval = retryInterval;
463 Sleep(sleepInterval * 1000);
465 retryInterval -= sleepInterval;
471 sprintf(msg, "Integrated login failed: %s", reason);
473 if (interactive && !failSilently)
474 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
479 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
481 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
483 DeregisterEventSource(h);
485 code = MapAuthError(code);
487 if (ISHIGHSECURITY(LogonOption) && (code!=0))
490 LocalFree(*lpLogonScript);
491 *lpLogonScript = NULL;
492 if (!(afsWillAutoStart || ISLOGONINTEGRATED(LogonOption))) // its not running, so if not autostart or integrated logon then just skip
497 DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
501 DWORD APIENTRY NPPasswordChangeNotify(
502 LPCWSTR lpAuthentInfoType,
503 LPVOID lpAuthentInfo,
504 LPCWSTR lpPreviousAuthentInfoType,
505 LPVOID lpPreviousAuthentInfo,
506 LPWSTR lpStationName,
507 LPVOID StationHandle,
510 DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");