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"
27 char NPName[] = "System\\CurrentControlSet\\Services\\TransarcAFSDaemon\\NetworkProvider";
29 #define REG_CLIENT_PARMS_KEY "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters"
30 #define REG_CLIENT_RETRY_INTERVAL_PARM "LoginRetryInterval"
31 #define REG_CLIENT_FAIL_SILENTLY_PARM "FailLoginsSilently"
32 #define DEFAULT_RETRY_INTERVAL 30 // seconds
33 #define DEFAULT_FAIL_SILENTLY FALSE
34 #define DEFAULT_SLEEP_INTERVAL 5 // seconds
37 /* Structure def copied from DDK (NTDEF.H) */
38 typedef struct UNICODE_STRING {
39 USHORT Length; /* number of bytes of Buffer actually used */
40 USHORT MaximumLength; /* sizeof buffer in bytes */
41 WCHAR *Buffer; /* 16 bit characters */
44 /* Structure def copied from NP API documentation */
45 typedef struct _MSV1_0_INTERACTIVE_LOGON {
46 DWORD MessageType; /* Actually this is an enum; ignored */
47 UNICODE_STRING LogonDomainName;
48 UNICODE_STRING UserName;
49 UNICODE_STRING Password;
50 } MSV1_0_INTERACTIVE_LOGON;
55 * We get a logon script pathname from the HKEY_LOCAL_MACHINE registry.
56 * I don't know what good this does; I just copied it from DFS.
58 * Returns NULL on failure.
60 WCHAR *GetLogonScript(void)
64 DWORD LSPtype, LSPsize;
68 * Get Network Provider key.
69 * Assume this works or we wouldn't be here.
71 (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, NPName,
72 0, KEY_QUERY_VALUE, &NPKey);
75 * Get Logon Script pathname length
77 code = RegQueryValueEx(NPKey, "LogonScript", NULL,
78 &LSPtype, NULL, &LSPsize);
85 if (LSPtype != REG_SZ) { /* Maybe handle REG_EXPAND_SZ? */
90 script = (WCHAR *)LocalAlloc(LMEM_FIXED, LSPsize);
93 * Explicitly call UNICODE version
94 * Assume it will succeed since it did before
96 (void) RegQueryValueExW(NPKey, L"LogonScript", NULL,
97 &LSPtype, (LPBYTE)script, &LSPsize);
103 BOOLEAN AFSWillAutoStart(void)
108 BOOLEAN result = FALSE;
109 LPQUERY_SERVICE_CONFIG pConfig = NULL;
113 /* Open services manager */
114 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
115 if (!scm) return FALSE;
117 /* Open AFSD service */
118 svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
122 /* Query AFSD service config, first just to get buffer size */
123 /* Expected to fail, so don't test return value */
124 (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
125 status = GetLastError();
126 if (status != ERROR_INSUFFICIENT_BUFFER)
129 /* Allocate buffer */
130 pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED, BufSize);
134 /* Query AFSD service config, this time for real */
135 flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
139 /* Is it autostart? */
140 if (pConfig->dwStartType < SERVICE_DEMAND_START)
146 CloseServiceHandle(svc);
148 CloseServiceHandle(scm);
153 DWORD MapAuthError(DWORD code)
156 case INTK_BADPW: return WN_BAD_PASSWORD;
157 case KERB_ERR_PRINCIPAL_UNKNOWN: return WN_BAD_USER;
158 default: return WN_NO_NETWORK;
162 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
166 case DLL_PROCESS_ATTACH:
167 /* Initialize AFS libraries */
172 /* Everything else succeeds but does nothing. */
173 case DLL_PROCESS_DETACH:
174 case DLL_THREAD_ATTACH:
175 case DLL_THREAD_DETACH:
183 DWORD APIENTRY NPGetCaps(DWORD index)
187 /* Don't have our own type; use somebody else's. */
188 return WNNC_NET_SUN_PC_NFS;
194 static void GetLoginBehavior(int *pRetryInterval, BOOLEAN *pFailSilently)
200 result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY, 0, KEY_QUERY_VALUE, &hKey);
201 if (result != ERROR_SUCCESS) {
202 *pRetryInterval = DEFAULT_RETRY_INTERVAL;
203 *pFailSilently = DEFAULT_FAIL_SILENTLY;
207 result = RegQueryValueEx(hKey, REG_CLIENT_RETRY_INTERVAL_PARM, 0, 0, (BYTE *)pRetryInterval, &dummyLen);
208 if (result != ERROR_SUCCESS)
209 *pRetryInterval = DEFAULT_RETRY_INTERVAL;
211 result = RegQueryValueEx(hKey, REG_CLIENT_FAIL_SILENTLY_PARM, 0, 0, (BYTE *)pFailSilently, &dummyLen);
212 if (result != ERROR_SUCCESS)
213 *pFailSilently = DEFAULT_FAIL_SILENTLY;
215 // Make sure this is really a bool value in the strict sense
216 *pFailSilently = !!*pFailSilently;
221 DWORD APIENTRY NPLogonNotify(
223 LPCWSTR lpAuthentInfoType,
224 LPVOID lpAuthentInfo,
225 LPCWSTR lpPreviousAuthentInfoType,
226 LPVOID lpPreviousAuthentInfo,
227 LPWSTR lpStationName,
228 LPVOID StationHandle,
229 LPWSTR *lpLogonScript)
234 MSV1_0_INTERACTIVE_LOGON *IL;
240 HWND hwndOwner = (HWND)StationHandle;
241 BOOLEAN failSilently;
243 int sleepInterval = DEFAULT_SLEEP_INTERVAL; // seconds
244 BOOLEAN afsWillAutoStart;
246 IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
248 /* Are we interactive? */
249 interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
251 /* Convert from Unicode to ANSI */
252 wcstombs(uname, IL->UserName.Buffer, 256);
253 wcstombs(password, IL->Password.Buffer, 256);
255 /* Check for zero length password */
256 if (password[0] == 0) {
258 reason = "zero length password is illegal";
263 code = cm_GetRootCellName(cell);
266 reason = "unknown cell";
270 /* Get user specified login behavior (or defaults) */
271 GetLoginBehavior(&retryInterval, &failSilently);
273 afsWillAutoStart = AFSWillAutoStart();
275 /* Possibly loop until AFS is started. */
277 code = ka_UserAuthenticateGeneral(
278 KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
279 uname, "", cell, password, 0, &pw_exp, 0,
282 /* If we've failed because the client isn't running yet and the
283 * client is set to autostart (and therefore it makes sense for
284 * us to wait for it to start) then sleep a while and try again.
285 * If the error was something else, then give up. */
286 if (code != KTC_NOCM && code != KTC_NOCMRPC || !afsWillAutoStart)
289 /* If the retry interval has expired and we still aren't
290 * logged in, then just give up if we are not in interactive
291 * mode or the failSilently flag is set, otherwise let the
292 * user know we failed and give them a chance to try again. */
293 if (retryInterval <= 0) {
294 if (!interactive || failSilently)
297 flag = MessageBox(hwndOwner,
298 "AFS is still starting. Retry?",
300 MB_ICONQUESTION | MB_RETRYCANCEL);
301 if (flag == IDCANCEL)
304 /* Wait just a little while and try again */
305 retryInterval = sleepInterval = DEFAULT_SLEEP_INTERVAL;
308 if (retryInterval < sleepInterval)
309 sleepInterval = retryInterval;
311 Sleep(sleepInterval * 1000);
313 retryInterval -= sleepInterval;
320 sprintf(msg, "Integrated login failed: %s", reason);
322 if (interactive && !failSilently)
323 MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
328 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
330 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
332 DeregisterEventSource(h);
336 /* Get logon script */
338 *lpLogonScript = GetLogonScript();
341 code = MapAuthError(code);
348 DWORD APIENTRY NPPasswordChangeNotify(
349 LPCWSTR lpAuthentInfoType,
350 LPVOID lpAuthentInfo,
351 LPCWSTR lpPreviousAuthentInfoType,
352 LPVOID lpPreviousAuthentInfo,
353 LPWSTR lpStationName,
354 LPVOID StationHandle,