csc_policy_logon_updates-20040503
[openafs.git] / src / WINNT / afsd / afslogon.c
index c95410a..9e6bac9 100644 (file)
@@ -1,11 +1,12 @@
-/* 
- * Copyright (C) 1998, 1989 Transarc Corporation - All rights reserved
- *
- * (C) COPYRIGHT IBM CORPORATION 1987, 1988
- * LICENSED MATERIALS - PROPERTY OF IBM
- *
- *
+/*
+ * Copyright 2000, International Business Machines Corporation and others.
+ * All Rights Reserved.
+ * 
+ * This software has been released under the terms of the IBM Public
+ * License.  For details, see the LICENSE file in the top-level source
+ * directory or online at http://www.openafs.org/dl/license10.html
  */
+
 #include <afs/param.h>
 #include <afs/stds.h>
 
 #include "cm_config.h"
 #include "krb.h"
 
+#include <io.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+DWORD LogonOption,TraceOption;
 
 HANDLE hDLL;
 
 WSADATA WSAjunk;
 
-char NPName[] = "System\\CurrentControlSet\\Services\\TransarcAFSDaemon\\NetworkProvider";
-
 #define REG_CLIENT_PARMS_KEY            "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters"
+#define REG_CLIENT_PROVIDER_KEY                        "SYSTEM\\CurrentControlSet\\Services\\TransarcAFSDaemon\\NetworkProvider"
 #define REG_CLIENT_RETRY_INTERVAL_PARM  "LoginRetryInterval"
 #define REG_CLIENT_FAIL_SILENTLY_PARM   "FailLoginsSilently"
-#define DEFAULT_RETRY_INTERVAL          30                        // seconds
+#define DEFAULT_RETRY_INTERVAL          30                        /* seconds*/
 #define DEFAULT_FAIL_SILENTLY           FALSE
-#define DEFAULT_SLEEP_INTERVAL          5                         // seconds
+#define DEFAULT_SLEEP_INTERVAL          5                         /* seconds*/
+
+#define ISLOGONINTEGRATED(v) ( ((v) & LOGON_OPTION_INTEGRATED)==LOGON_OPTION_INTEGRATED)
+#define ISHIGHSECURITY(v) ( ((v) & LOGON_OPTION_HIGHSECURITY)==LOGON_OPTION_HIGHSECURITY)
 
+#define TRACE_OPTION_EVENT 1
+#define ISLOGONTRACE(v) ( ((v) & TRACE_OPTION_EVENT)==TRACE_OPTION_EVENT)
 
 /* Structure def copied from DDK (NTDEF.H) */
 typedef struct UNICODE_STRING {
@@ -56,24 +67,66 @@ typedef struct _MSV1_0_INTERACTIVE_LOGON {
  *
  * Returns NULL on failure.
  */
-WCHAR *GetLogonScript(void)
+
+
+void DebugEvent0(char *a) 
+{
+       HANDLE h; char *ptbuf[1];
+       if (!ISLOGONTRACE(TraceOption))
+               return;
+       h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
+       ptbuf[0] = a;
+       ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
+       DeregisterEventSource(h);
+}
+
+#define MAXBUF_ 131
+void DebugEvent(char *a,char *b,...) 
+{
+       HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
+       va_list marker;
+       if (!ISLOGONTRACE(TraceOption))
+               return;
+       h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
+       va_start(marker,b);
+       _vsnprintf(buf,MAXBUF_,b,marker);
+    buf[MAXBUF_] = '\0';
+       ptbuf[0] = buf;
+       ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);\
+       DeregisterEventSource(h);
+       va_end(marker);
+}
+
+CHAR *GenRandomName(CHAR *pbuf)
 {
-       WCHAR *script;
+       int i;
+       srand( (unsigned)time( NULL ) );
+       for (i=0;i<MAXRANDOMNAMELEN-1;i++)
+               pbuf[i]='a'+(rand() % 26);
+       pbuf[MAXRANDOMNAMELEN-1]=0;
+       return pbuf;
+}
+
+WCHAR *GetLogonScript(CHAR *pname)
+{
+       WCHAR *script,*buf;
        DWORD code;
        DWORD LSPtype, LSPsize;
        HKEY NPKey;
+       WCHAR randomName[MAXRANDOMNAMELEN];
 
        /*
         * Get Network Provider key.
         * Assume this works or we wouldn't be here.
         */
-       (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, NPName,
+       (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PROVIDER_KEY,
                            0, KEY_QUERY_VALUE, &NPKey);
 
        /*
         * Get Logon Script pathname length
         */
-       code = RegQueryValueEx(NPKey, "LogonScript", NULL,
+
+       code = RegQueryValueExW(NPKey, L"LogonScript", NULL,
                                &LSPtype, NULL, &LSPsize);
 
        if (code) {
@@ -86,14 +139,29 @@ WCHAR *GetLogonScript(void)
                return NULL;
        }
 
-       script = (WCHAR *)LocalAlloc(LMEM_FIXED, LSPsize);
-
+       buf=(WCHAR *)LocalAlloc(LMEM_FIXED,LSPsize);
+       script=(WCHAR *)LocalAlloc(LMEM_FIXED,LSPsize+(MAXRANDOMNAMELEN)*sizeof(WCHAR));
        /*
         * Explicitly call UNICODE version
         * Assume it will succeed since it did before
         */
        (void) RegQueryValueExW(NPKey, L"LogonScript", NULL,
-                               &LSPtype, (LPBYTE)script, &LSPsize);
+                               &LSPtype, (LPBYTE)buf, &LSPsize);
+       MultiByteToWideChar(CP_ACP,0,pname,strlen(pname)+1,randomName,(strlen(pname)+1)*sizeof(WCHAR));
+       swprintf(script,buf,randomName);
+       LocalFree(buf);
+
+#ifdef DEBUG_VERBOSE
+    {
+        HANDLE h; char *ptbuf[1],buf[132],tbuf[255];
+               WideCharToMultiByte(CP_ACP,0,script,LSPsize,tbuf,255,NULL,NULL);
+        h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
+        sprintf(buf, "Script[%s,%d] Return Code[%x]",tbuf,LSPsize,code);
+        ptbuf[0] = buf;
+        ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, ptbuf, NULL);
+        DeregisterEventSource(h);
+    }
+#endif
 
        RegCloseKey (NPKey);
        return script;
@@ -126,7 +194,7 @@ BOOLEAN AFSWillAutoStart(void)
                goto close_svc;
 
        /* Allocate buffer */
-       pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED, BufSize);
+       pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
        if (!pConfig)
                goto close_svc;
 
@@ -152,9 +220,12 @@ close_scm:
 DWORD MapAuthError(DWORD code)
 {
        switch (code) {
-               case INTK_BADPW: return WN_BAD_PASSWORD;
-               case KERB_ERR_PRINCIPAL_UNKNOWN: return WN_BAD_USER;
-               default: return WN_NO_NETWORK;
+       case KTC_NOCM:
+       case KTC_NOCMRPC:
+               return WN_NO_NETWORK;
+/*     case INTK_BADPW: return WN_BAD_PASSWORD;*/
+/*     case KERB_ERR_PRINCIPAL_UNKNOWN: return WN_BAD_USER;*/
+       default: return WN_SUCCESS;
        }
 }
 
@@ -165,6 +236,7 @@ BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
                case DLL_PROCESS_ATTACH:
                        /* Initialize AFS libraries */
                        rx_Init(0);
+            initAFSDirPath();
                        ka_Init(0);
                        break;
 
@@ -192,30 +264,52 @@ DWORD APIENTRY NPGetCaps(DWORD index)
 
 static void GetLoginBehavior(int *pRetryInterval, BOOLEAN *pFailSilently)
 {
-        long result;
-        HKEY hKey;
-        DWORD dummyLen;
+    long result;
+    HKEY hKey;
+    DWORD dummyLen;
                 
        result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY, 0, KEY_QUERY_VALUE, &hKey);
-        if (result != ERROR_SUCCESS) {
-                *pRetryInterval = DEFAULT_RETRY_INTERVAL;
-                *pFailSilently = DEFAULT_FAIL_SILENTLY;
-                return;
-        }
+    if (result != ERROR_SUCCESS) {
+        *pRetryInterval = DEFAULT_RETRY_INTERVAL;
+        *pFailSilently = DEFAULT_FAIL_SILENTLY;
+        return;
+    }
         
-               result = RegQueryValueEx(hKey, REG_CLIENT_RETRY_INTERVAL_PARM, 0, 0, (BYTE *)pRetryInterval, &dummyLen);
-               if (result != ERROR_SUCCESS)
-                       *pRetryInterval = DEFAULT_RETRY_INTERVAL;
+    result = RegQueryValueEx(hKey, REG_CLIENT_RETRY_INTERVAL_PARM, 0, 0, (BYTE *)pRetryInterval, &dummyLen);
+    if (result != ERROR_SUCCESS)
+        *pRetryInterval = DEFAULT_RETRY_INTERVAL;
                        
-               result = RegQueryValueEx(hKey, REG_CLIENT_FAIL_SILENTLY_PARM, 0, 0, (BYTE *)pFailSilently, &dummyLen);
-               if (result != ERROR_SUCCESS)
-                       *pFailSilently = DEFAULT_FAIL_SILENTLY;
+    result = RegQueryValueEx(hKey, REG_CLIENT_FAIL_SILENTLY_PARM, 0, 0, (BYTE *)pFailSilently, &dummyLen);
+    if (result != ERROR_SUCCESS)
+        *pFailSilently = DEFAULT_FAIL_SILENTLY;
 
-        // Make sure this is really a bool value in the strict sense
-        *pFailSilently = !!*pFailSilently;
-                       
-        RegCloseKey(hKey);
-}
+    /* Make sure this is really a bool value in the strict sense*/
+    *pFailSilently = !!*pFailSilently;
+
+    RegCloseKey(hKey);
+}   
+
+BOOL IsServiceRunning (void)
+{
+    SERVICE_STATUS Status;
+    SC_HANDLE hManager;
+    memset (&Status, 0x00, sizeof(Status));
+    Status.dwCurrentState = SERVICE_STOPPED;
+
+    if ((hManager = OpenSCManager (NULL, NULL, GENERIC_READ)) != NULL)
+    {
+        SC_HANDLE hService;
+        if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), GENERIC_READ)) != NULL)
+        {
+            QueryServiceStatus (hService, &Status);
+            CloseServiceHandle (hService);
+        }
+
+        CloseServiceHandle (hManager);
+    }
+    DebugEvent("AFS AfsLogon - Test Service Running","Return Code[%x] ?Running[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_RUNNING));
+    return (Status.dwCurrentState == SERVICE_RUNNING);
+}   
 
 DWORD APIENTRY NPLogonNotify(
        PLUID lpLogonId,
@@ -227,20 +321,28 @@ DWORD APIENTRY NPLogonNotify(
        LPVOID StationHandle,
        LPWSTR *lpLogonScript)
 {
-       char uname[256];
-       char password[256];
-       char cell[256];
+       char uname[256]="";
+       char *ctemp;
+       char password[256]="";
+       char cell[256]="<non-integrated logon>";
        MSV1_0_INTERACTIVE_LOGON *IL;
        DWORD code;
        int pw_exp;
        char *reason;
        BOOLEAN interactive;
        BOOLEAN flag;
+       DWORD LSPtype, LSPsize;
+       HKEY NPKey;
        HWND hwndOwner = (HWND)StationHandle;
-        BOOLEAN failSilently;
-        int retryInterval;
-        int sleepInterval = DEFAULT_SLEEP_INTERVAL;        // seconds        
-        BOOLEAN afsWillAutoStart;
+    BOOLEAN failSilently;
+    int retryInterval;
+    int sleepInterval = DEFAULT_SLEEP_INTERVAL;        /* seconds        */
+    BOOLEAN afsWillAutoStart;
+       CHAR RandomName[MAXRANDOMNAMELEN];
+    BOOLEAN uppercased_name = TRUE;
+
+    /* Initialize Logon Script to none */
+       *lpLogonScript=NULL;
         
        IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
 
@@ -251,96 +353,183 @@ DWORD APIENTRY NPLogonNotify(
        wcstombs(uname, IL->UserName.Buffer, 256);
        wcstombs(password, IL->Password.Buffer, 256);
 
-       /* Check for zero length password */
-       if (password[0] == 0) {
-               code = GT_PW_NULL;
-               reason = "zero length password is illegal";
-               goto checkauth;
-       }
+       /* Make sure AD-DOMANS sent from login that is sent to us is striped */
+    ctemp = strchr(uname, '@');
+    if (ctemp) *ctemp = 0;
 
-       /* Get cell name */
-       code = cm_GetRootCellName(cell);
-       if (code < 0) {
-               code = KTC_NOCELL;
-               reason = "unknown cell";
-               goto checkauth;
-       }
+    /* is the name all uppercase? */
+    for ( ctemp = uname; *ctemp ; ctemp++) {
+        if ( islower(*ctemp) ) {
+            uppercased_name = FALSE;
+            break;
+        }
+    }
+
+       (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
+                        0, KEY_QUERY_VALUE, &NPKey);
+       LSPsize=sizeof(TraceOption);
+       RegQueryValueEx(NPKey, "TraceOption", NULL,
+                     &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
+    RegCloseKey (NPKey);
+       
+       /*
+        * Get Logon OPTIONS
+        */
+
+       (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PROVIDER_KEY,
+                         0, KEY_QUERY_VALUE, &NPKey);
+
+       LSPsize=sizeof(LogonOption);
+       code = RegQueryValueEx(NPKey, "LogonOptions", NULL,
+                            &LSPtype, (LPBYTE)&LogonOption, &LSPsize);
+
+       RegCloseKey (NPKey);
+       if ((code!=0) || (LSPtype!=REG_DWORD))
+               LogonOption=LOGON_OPTION_INTEGRATED;    /*default to integrated logon only*/
 
-        /* Get user specified login behavior (or defaults) */
-        GetLoginBehavior(&retryInterval, &failSilently);
+       afsWillAutoStart = AFSWillAutoStart();
         
-        afsWillAutoStart = AFSWillAutoStart();
+       DebugEvent("AFS AfsLogon - NPLogonNotify","LogonOption[%x], Service AutoStart[%d]",
+                LogonOption,afsWillAutoStart);
+    
+    /* Get local machine specified login behavior (or defaults) */
+    GetLoginBehavior(&retryInterval, &failSilently);
         
-        /* Possibly loop until AFS is started. */
-        while (1) {
-                code = ka_UserAuthenticateGeneral(
-                       KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
-                       uname, "", cell, password, 0, &pw_exp, 0,
-                       &reason);
-                       
+    /* Check for zero length password if integrated logon*/
+       if ( ISLOGONINTEGRATED(LogonOption) )  {
+        if ( password[0] == 0 ) {
+            code = GT_PW_NULL;
+            reason = "zero length password is illegal";
+            code=0;
+        }
+
+        /* Get cell name if doing integrated logon */
+               code = cm_GetRootCellName(cell);
+               if (code < 0) { 
+                       code = KTC_NOCELL;
+                       reason = "unknown cell";
+                       code=0;
+               }
+
+        /*only do if high security option is on*/
+        if (ISHIGHSECURITY(LogonOption))
+            *lpLogonScript = GetLogonScript(GenRandomName(RandomName));        
+    }
+
+    /* loop until AFS is started. */
+    while (TRUE) {
+        code=0;
+               
+        /* is service started yet?*/
+        DebugEvent("AFS AfsLogon - ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s]",
+                   code,uname,cell);
+
+        /* if Integrated Logon only */
+        if (ISLOGONINTEGRATED(LogonOption) && !ISHIGHSECURITY(LogonOption))
+               {                       
+                       code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
+                                                uname, "", cell, password,uname, 0, &pw_exp, 0,
+                                                &reason);
+                       DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2","Code[%x]",
+                        code);
+            if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && uppercased_name ) {
+                for ( ctemp = uname; *ctemp ; ctemp++) {
+                    *ctemp = tolower(*ctemp);
+                }
+                uppercased_name = FALSE;
+                continue;
+            }
+               } 
+        /* if Integrated Logon and High Security pass random generated name*/
+        else if (ISLOGONINTEGRATED(LogonOption) && ISHIGHSECURITY(LogonOption))
+               {
+                       code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
+                                                uname, "", cell, password,RandomName, 0, &pw_exp, 0,
+                                                &reason);
+                       DebugEvent("AFS AfsLogon - (Both)ka_UserAuthenticateGeneral2","Code[%x] RandomName[%s]",
+                       code, RandomName);
+
+            if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && uppercased_name ) {
+                for ( ctemp = uname; *ctemp ; ctemp++) {
+                    *ctemp = tolower(*ctemp);
+                }
+                uppercased_name = FALSE;
+                continue;
+            }
+               } else {  
+            /*JUST check to see if its running*/
+                   if (IsServiceRunning())
+                break;
+                   code = KTC_NOCM;
+                   if (!afsWillAutoStart)
+                break;
+               }
+
                /* If we've failed because the client isn't running yet and the
-                * client is set to autostart (and therefore it makes sense for
-                * us to wait for it to start) then sleep a while and try again. 
-                * If the error was something else, then give up. */
+         * client is set to autostart (and therefore it makes sense for
+         * us to wait for it to start) then sleep a while and try again. 
+         * If the error was something else, then give up. */
                if (code != KTC_NOCM && code != KTC_NOCMRPC || !afsWillAutoStart)
-                       break;
+                       break;
                
-                /* If the retry interval has expired and we still aren't
-                 * logged in, then just give up if we are not in interactive
-                 * mode or the failSilently flag is set, otherwise let the
-                 * user know we failed and give them a chance to try again. */
-                if (retryInterval <= 0) {
-                        if (!interactive || failSilently)
-                                break;
-
+        /* If the retry interval has expired and we still aren't
+         * logged in, then just give up if we are not in interactive
+         * mode or the failSilently flag is set, otherwise let the
+         * user know we failed and give them a chance to try again. */
+        if (retryInterval <= 0) {
+            reason = "AFS not running";
+            if (!interactive || failSilently)
+                break;
                        flag = MessageBox(hwndOwner,
-                               "AFS is still starting.  Retry?",
-                               "AFS Logon",
-                               MB_ICONQUESTION | MB_RETRYCANCEL);
+                               "AFS is still starting.  Retry?",
+                               "AFS Logon",
+                               MB_ICONQUESTION | MB_RETRYCANCEL);
                        if (flag == IDCANCEL)
-                               break;
-                        
-                        /* Wait just a little while and try again */
-                        retryInterval = sleepInterval = DEFAULT_SLEEP_INTERVAL;
-                }
-                                        
-                if (retryInterval < sleepInterval)
-                        sleepInterval = retryInterval;
-                        
-                Sleep(sleepInterval * 1000);
+                break;
 
-                retryInterval -= sleepInterval;
+            /* Wait just a little while and try again */
+            retryInterval = sleepInterval = DEFAULT_SLEEP_INTERVAL;
         }
 
-checkauth:
+        if (retryInterval < sleepInterval)
+                       sleepInterval = retryInterval;
+
+               Sleep(sleepInterval * 1000);
+
+        retryInterval -= sleepInterval;
+    }
+
        if (code) {
-                char msg[128];
-                
-                sprintf(msg, "Integrated login failed: %s", reason);
-                
+        char msg[128];
+        sprintf(msg, "Integrated login failed: %s", reason);
+
                if (interactive && !failSilently)
                        MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
                else {
-                       HANDLE h;
-                       char *ptbuf[1];
-                
-                       h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
-                       ptbuf[0] = msg;
-                       ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
-                                   1, 0, ptbuf, NULL);
-                       DeregisterEventSource(h);
-                }
-       }
+            HANDLE h;
+            char *ptbuf[1];
+
+            h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
+            ptbuf[0] = msg;
+            ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1008, NULL,
+                         1, 0, ptbuf, NULL);
+            DeregisterEventSource(h);
+        }
+           code = MapAuthError(code);
+               SetLastError(code);
 
-       /* Get logon script */
-       if (interactive)
-               *lpLogonScript = GetLogonScript();
+               if (ISLOGONINTEGRATED(LogonOption) && (code!=0))
+               {
+                       if (*lpLogonScript)
+                               LocalFree(*lpLogonScript);
+                       *lpLogonScript = NULL;
+                       if (!afsWillAutoStart)  // its not running, so if not autostart or integrated logon then just skip
+                               code = 0;
 
-       if (code) {
-               code = MapAuthError(code);
-               SetLastError(code);
+               }
        }
 
+       DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
        return code;
 }
 
@@ -353,6 +542,7 @@ DWORD APIENTRY NPPasswordChangeNotify(
        LPVOID StationHandle,
        DWORD dwChangeInfo)
 {
+       DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
        return 0;
 }