windows-logon-20050630
[openafs.git] / src / WINNT / afsd / afslogon.c
index 3e63daa..506ea71 100644 (file)
@@ -15,6 +15,8 @@
 #include <fcntl.h>
 
 #include <winsock2.h>
+#include <lm.h>
+#include <nb30.h>
 
 #include <afs/param.h>
 #include <afs/stds.h>
@@ -25,6 +27,9 @@
 #include "cm_config.h"
 #include "krb.h"
 #include "afskfw.h"
+#include "lanahelper.h"
+
+#include <WINNT\afsreg.h>
 
 DWORD TraceOption = 0;
 
@@ -35,32 +40,34 @@ WSADATA WSAjunk;
 
 void DebugEvent0(char *a) 
 {
-       HANDLE h; char *ptbuf[1];
-       if (!ISLOGONTRACE(TraceOption))
-               return;
-       h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
-       ptbuf[0] = a;
-       ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
-       DeregisterEventSource(h);
+    HANDLE h; char *ptbuf[1];
+    
+    if (!ISLOGONTRACE(TraceOption))
+        return;
+    
+    h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
+    ptbuf[0] = a;
+    ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
+    DeregisterEventSource(h);
 }
 
 #define MAXBUF_ 512
 void DebugEvent(char *b,...) 
 {
-       HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
-       va_list marker;
+    HANDLE h; char *ptbuf[1],buf[MAXBUF_+1];
+    va_list marker;
 
-       if (!ISLOGONTRACE(TraceOption))
-               return;
+    if (!ISLOGONTRACE(TraceOption))
+        return;
 
-       h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
-       va_start(marker,b);
-       StringCbVPrintf(buf, MAXBUF_+1,b,marker);
+    h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
+    va_start(marker,b);
+    StringCbVPrintf(buf, MAXBUF_+1,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);
+    ptbuf[0] = buf;
+    ReportEvent(h, EVENTLOG_INFORMATION_TYPE, 0, 0, NULL, 1, 0, (const char **)ptbuf, NULL);
+    DeregisterEventSource(h);
+    va_end(marker);
 }
 
 static HANDLE hInitMutex = NULL;
@@ -68,8 +75,8 @@ static BOOL bInit = FALSE;
 
 BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
 {
-       hDLL = dll;
-       switch (reason) {
+    hDLL = dll;
+    switch (reason) {
     case DLL_PROCESS_ATTACH:
         /* Initialization Mutex */
         hInitMutex = CreateMutex(NULL, FALSE, NULL);
@@ -82,118 +89,153 @@ BOOLEAN APIENTRY DllEntryPoint(HANDLE dll, DWORD reason, PVOID reserved)
     case DLL_THREAD_ATTACH:
     case DLL_THREAD_DETACH:
     default:
-               /* Everything else succeeds but does nothing. */
+        /* Everything else succeeds but does nothing. */
         break;
-       }
+    }
 
-       return TRUE;
+    return TRUE;
 }
 
 void AfsLogonInit(void)
 {
     if ( bInit == FALSE ) {
-         if ( WaitForSingleObject( hInitMutex, INFINITE ) == WAIT_OBJECT_0 ) {
-             if ( bInit == FALSE ) {
-                 rx_Init(0);
-                 initAFSDirPath();
-                 ka_Init(0);
-                 bInit = TRUE;
-             }
-             ReleaseMutex(hInitMutex);
-         }
+        if ( WaitForSingleObject( hInitMutex, INFINITE ) == WAIT_OBJECT_0 ) {
+            if ( bInit == FALSE ) {
+                rx_Init(0);
+                initAFSDirPath();
+                ka_Init(0);
+                bInit = TRUE;
+            }
+            ReleaseMutex(hInitMutex);
+        }
     }
 }
 
 CHAR *GenRandomName(CHAR *pbuf)
 {
-       int i;
-       srand( (unsigned)time( NULL ) );
-       for (i=0;i<MAXRANDOMNAMELEN-1;i++)
-               pbuf[i]='a'+(rand() % 26);
-       pbuf[MAXRANDOMNAMELEN-1]=0;
-       return pbuf;
+    int i;
+    srand( (unsigned)time( NULL ) );
+    for (i=0;i<MAXRANDOMNAMELEN-1;i++)
+        pbuf[i]='a'+(rand() % 26);
+    pbuf[MAXRANDOMNAMELEN-1]=0;
+    return pbuf;
 }
 
 BOOLEAN AFSWillAutoStart(void)
 {
-       SC_HANDLE scm;
-       SC_HANDLE svc;
-       BOOLEAN flag;
-       BOOLEAN result = FALSE;
-       LPQUERY_SERVICE_CONFIG pConfig = NULL;
-       DWORD BufSize;
-       LONG status;
-
-       /* Open services manager */
-       scm = OpenSCManager(NULL, NULL, GENERIC_READ);
-       if (!scm) return FALSE;
-
-       /* Open AFSD service */
-       svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
-       if (!svc)
-               goto close_scm;
-
-       /* Query AFSD service config, first just to get buffer size */
-       /* Expected to fail, so don't test return value */
-       (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
-       status = GetLastError();
-       if (status != ERROR_INSUFFICIENT_BUFFER)
-               goto close_svc;
-
-       /* Allocate buffer */
-       pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
-       if (!pConfig)
-               goto close_svc;
-
-       /* Query AFSD service config, this time for real */
-       flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
-       if (!flag)
-               goto free_pConfig;
-
-       /* Is it autostart? */
-       if (pConfig->dwStartType < SERVICE_DEMAND_START)
-               result = TRUE;
-
-free_pConfig:
-       GlobalFree(pConfig);
-close_svc:
-       CloseServiceHandle(svc);
-close_scm:
-       CloseServiceHandle(scm);
-
-       return result;
+    SC_HANDLE scm;
+    SC_HANDLE svc;
+    BOOLEAN flag;
+    BOOLEAN result = FALSE;
+    LPQUERY_SERVICE_CONFIG pConfig = NULL;
+    DWORD BufSize;
+    LONG status;
+
+    /* Open services manager */
+    scm = OpenSCManager(NULL, NULL, GENERIC_READ);
+    if (!scm) return FALSE;
+
+    /* Open AFSD service */
+    svc = OpenService(scm, "TransarcAFSDaemon", SERVICE_QUERY_CONFIG);
+    if (!svc)
+        goto close_scm;
+
+    /* Query AFSD service config, first just to get buffer size */
+    /* Expected to fail, so don't test return value */
+    (void) QueryServiceConfig(svc, NULL, 0, &BufSize);
+    status = GetLastError();
+    if (status != ERROR_INSUFFICIENT_BUFFER)
+        goto close_svc;
+
+    /* Allocate buffer */
+    pConfig = (LPQUERY_SERVICE_CONFIG)GlobalAlloc(GMEM_FIXED,BufSize);
+    if (!pConfig)
+        goto close_svc;
+
+    /* Query AFSD service config, this time for real */
+    flag = QueryServiceConfig(svc, pConfig, BufSize, &BufSize);
+    if (!flag)
+        goto free_pConfig;
+
+    /* Is it autostart? */
+    if (pConfig->dwStartType < SERVICE_DEMAND_START)
+        result = TRUE;
+
+  free_pConfig:
+    GlobalFree(pConfig);
+  close_svc:
+    CloseServiceHandle(svc);
+  close_scm:
+    CloseServiceHandle(scm);
+
+    return result;
 }
 
 DWORD MapAuthError(DWORD code)
 {
-       switch (code) {
-               /* Unfortunately, returning WN_NO_NETWORK results in the MPR abandoning
-                * logon scripts for all credential managers, although they will still
-                * receive logon notifications.  Since we don't want this, we return
-                * WN_SUCCESS.  This is highly undesirable, but we also don't want to
-                * break other network providers.
-                */
-/*     case KTC_NOCM:
-       case KTC_NOCMRPC:
-               return WN_NO_NETWORK; */
-       default: return WN_SUCCESS;
-       }
+    switch (code) {
+        /* Unfortunately, returning WN_NO_NETWORK results in the MPR abandoning
+         * logon scripts for all credential managers, although they will still
+         * receive logon notifications.  Since we don't want this, we return
+         * WN_SUCCESS.  This is highly undesirable, but we also don't want to
+         * break other network providers.
+         */
+ /* case KTC_NOCM:
+    case KTC_NOCMRPC:
+    return WN_NO_NETWORK; */
+    default: return WN_SUCCESS;
+  }
 }
 
 DWORD APIENTRY NPGetCaps(DWORD index)
 {
-       switch (index) {
-               case WNNC_NET_TYPE:
-                       /* Don't have our own type; use somebody else's. */
-                       return WNNC_NET_SUN_PC_NFS;
-
-               case WNNC_START:
-                       /* Say we are already started, even though we might wait after we receive NPLogonNotify */
-                       return 1;
-
-               default:
-                       return 0;
-       }
+    switch (index) {
+    case WNNC_NET_TYPE:
+        /* Don't have our own type; use somebody else's. */
+        return WNNC_NET_SUN_PC_NFS;
+
+    case WNNC_START:
+        /* Say we are already started, even though we might wait after we receive NPLogonNotify */
+        return 1;
+
+    default:
+        return 0;
+    }
+}       
+
+NET_API_STATUS 
+NetUserGetProfilePath( LPCWSTR Domain, LPCWSTR UserName, char * profilePath, 
+                       DWORD profilePathLen )
+{
+    NET_API_STATUS code;
+    LPWSTR ServerName = NULL;
+    LPUSER_INFO_3 p3 = NULL;
+
+    NetGetAnyDCName(NULL, Domain, (LPBYTE *)&ServerName);
+    /* if NetGetAnyDCName fails, ServerName == NULL
+     * NetUserGetInfo will obtain local user information 
+     */
+    code = NetUserGetInfo(ServerName, UserName, 3, (LPBYTE *)&p3);
+    if (code == NERR_Success)
+    {
+        code = NERR_UserNotFound;
+        if (p3) {
+            if (p3->usri3_profile) {
+                DWORD len = lstrlenW(p3->usri3_profile);
+                if (len > 0) {
+                    /* Convert From Unicode to ANSI (UTF-8 for future) */
+                    len = len < profilePathLen ? len : profilePathLen - 1;
+                    WideCharToMultiByte(CP_UTF8, 0, p3->usri3_profile, len, profilePath, len, NULL, NULL);
+                    profilePath[len] = '\0';
+                    code = NERR_Success;
+                }
+            }
+            NetApiBufferFree(p3);
+        }
+    }
+    if (ServerName) 
+        NetApiBufferFree(ServerName);
+    return code;
 }
 
 BOOL IsServiceRunning (void)
@@ -218,6 +260,28 @@ BOOL IsServiceRunning (void)
     return (Status.dwCurrentState == SERVICE_RUNNING);
 }   
 
+BOOL IsServiceStartPending (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 Start Pending","Return Code[%x] ?Start Pending[%d]",Status.dwCurrentState,(Status.dwCurrentState == SERVICE_START_PENDING));
+    return (Status.dwCurrentState == SERVICE_START_PENDING);
+}   
+
 /* LOOKUPKEYCHAIN: macro to look up the value in the list of keys in order until it's found
    v:variable to receive value (reference type)
    t:type
@@ -251,235 +315,278 @@ BOOL IsServiceRunning (void)
 /* Get domain specific configuration info.  We are returning void because if anything goes wrong
    we just return defaults.
  */
-void GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
-       HKEY hkParm = NULL; /* Service parameter */
-       HKEY hkNp = NULL;   /* network provider key */
-       HKEY hkDoms = NULL; /* domains key */
-       HKEY hkDom = NULL;  /* DOMAINS/domain key */
-       HKEY hkTemp = NULL;
-       LONG rv;
-       DWORD dwSize;
-       DWORD dwType;
-       DWORD dwDummy;
-       char computerName[MAX_COMPUTERNAME_LENGTH + 1];
-       char *effDomain;
-
-       DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
-       /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
-       opt->flags = LOGON_FLAG_REMOTE;
-       if(domain) {
-               dwSize = MAX_COMPUTERNAME_LENGTH;
-               if(GetComputerName(computerName, &dwSize)) {
-                       if(!stricmp(computerName, domain)) {
-                               effDomain = "LOCALHOST";
-                               opt->flags = LOGON_FLAG_LOCAL;
-                       }
-                       else
-                               effDomain = domain;
-               }
-       } else
-               effDomain = NULL;
-
-       rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY, 0, KEY_READ, &hkParm );
-       if(rv != ERROR_SUCCESS) {
-               hkParm = NULL;
-               DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
-       }
-
-       rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REG_CLIENT_PROVIDER_KEY, 0, KEY_READ, &hkNp );
-       if(rv != ERROR_SUCCESS) {
-               hkNp = NULL;
-               DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
-       }
-
-       if(hkNp) {
-               rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
-               if( rv != ERROR_SUCCESS ) {
-                       hkDoms = NULL;
-                       DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
-               }
-       }
-
-       if(hkDoms && effDomain) {
-               rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
-               if( rv != ERROR_SUCCESS ) {
-                       hkDom = NULL;
-                       DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
-                       /* If none of the domains match, we shouldn't use the domain key either */
-                       RegCloseKey(hkDoms);
-                       hkDoms = NULL;
-               }
-       } else
-               DebugEvent("Not opening domain key for [%s]", effDomain);
-
-       /* Each individual can either be specified on the domain key, the domains key or in the
-          net provider key.  They fail over in that order.  If none is found, we just use the 
-          defaults. */
-
-       /* LogonOption */
-       LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
-
-       /* FailLoginsSilently */
-       dwSize = sizeof(dwDummy);
-       rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
-       if(rv != ERROR_SUCCESS)
-               LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
+void 
+GetDomainLogonOptions( PLUID lpLogonId, char * username, char * domain, LogonOptions_t *opt ) {
+    HKEY hkParm = NULL; /* Service parameter */
+    HKEY hkNp = NULL;   /* network provider key */
+    HKEY hkDoms = NULL; /* domains key */
+    HKEY hkDom = NULL;  /* DOMAINS/domain key */
+    HKEY hkTemp = NULL;
+    LONG rv;
+    DWORD dwSize;
+    DWORD dwType;
+    DWORD dwDummy;
+    char computerName[MAX_COMPUTERNAME_LENGTH + 1];
+    char *effDomain;
+
+    memset(opt, 0, sizeof(LogonOptions_t));
+
+    DebugEvent("In GetDomainLogonOptions for user [%s] in domain [%s]", username, domain);
+    /* If the domain is the same as the Netbios computer name, we use the LOCALHOST domain name*/
+    opt->flags = LOGON_FLAG_REMOTE;
+    if(domain) {
+        dwSize = MAX_COMPUTERNAME_LENGTH;
+        if(GetComputerName(computerName, &dwSize)) {
+            if(!stricmp(computerName, domain)) {
+                effDomain = "LOCALHOST";
+                opt->flags = LOGON_FLAG_LOCAL;
+            }
+            else
+                effDomain = domain;
+        }
+    } else
+        effDomain = NULL;
+
+    rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY, 0, KEY_READ, &hkParm );
+    if(rv != ERROR_SUCCESS) {
+        hkParm = NULL;
+        DebugEvent("GetDomainLogonOption: Can't open parms key [%d]", rv);
+    }
+
+    rv = RegOpenKeyEx( HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PROVIDER_SUBKEY, 0, KEY_READ, &hkNp );
+    if(rv != ERROR_SUCCESS) {
+        hkNp = NULL;
+        DebugEvent("GetDomainLogonOptions: Can't open NP key [%d]", rv);
+    }
+
+    if(hkNp) {
+        rv = RegOpenKeyEx( hkNp, REG_CLIENT_DOMAINS_SUBKEY, 0, KEY_READ, &hkDoms );
+        if( rv != ERROR_SUCCESS ) {
+            hkDoms = NULL;
+            DebugEvent("GetDomainLogonOptions: Can't open Domains key [%d]", rv);
+        }
+    }
+
+    if(hkDoms && effDomain) {
+        rv = RegOpenKeyEx( hkDoms, effDomain, 0, KEY_READ, &hkDom );
+        if( rv != ERROR_SUCCESS ) {
+            hkDom = NULL;
+            DebugEvent("GetDomainLogonOptions: Can't open domain key for [%s] [%d]", effDomain, rv);
+            /* If none of the domains match, we shouldn't use the domain key either */
+            RegCloseKey(hkDoms);
+            hkDoms = NULL;
+        }
+    } else
+        DebugEvent("Not opening domain key for [%s]", effDomain);
+
+    /* Each individual can either be specified on the domain key, the domains key or in the
+       net provider key.  They fail over in that order.  If none is found, we just use the 
+       defaults. */
+
+    /* LogonOption */
+    LOOKUPKEYCHAIN(opt->LogonOption, REG_DWORD, DEFAULT_LOGON_OPTION, REG_CLIENT_LOGON_OPTION_PARM);
+
+    /* FailLoginsSilently */
+    dwSize = sizeof(dwDummy);
+    rv = RegQueryValueEx(hkParm, REG_CLIENT_FAIL_SILENTLY_PARM, 0, &dwType, (LPBYTE) &dwDummy, &dwSize);
+    if (rv != ERROR_SUCCESS)
+        LOOKUPKEYCHAIN(dwDummy, REG_DWORD, DEFAULT_FAIL_SILENTLY, REG_CLIENT_FAIL_SILENTLY_PARM);
     opt->failSilently = !!dwDummy;
 
-       /* Retry interval */
-       LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
+    /* Retry interval */
+    LOOKUPKEYCHAIN(opt->retryInterval, REG_DWORD, DEFAULT_RETRY_INTERVAL, REG_CLIENT_RETRY_INTERVAL_PARM);
 
-       /* Sleep interval */
-       LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
+    /* Sleep interval */
+    LOOKUPKEYCHAIN(opt->sleepInterval, REG_DWORD, DEFAULT_SLEEP_INTERVAL, REG_CLIENT_SLEEP_INTERVAL_PARM);
 
-       opt->logonScript = NULL;
-       opt->smbName = NULL;
+    opt->logonScript = NULL;
+    opt->smbName = NULL;
 
-       if(!ISLOGONINTEGRATED(opt->LogonOption)) {
-               goto cleanup; /* no need to lookup the logon script */
-       }
+    if(!ISLOGONINTEGRATED(opt->LogonOption)) {
+        goto cleanup; /* no need to lookup the logon script */
+    }
 
-       /* come up with SMB username */
-       if(ISHIGHSECURITY(opt->LogonOption)) {
+    /* come up with SMB username */
+    if(ISHIGHSECURITY(opt->LogonOption)) {
         opt->smbName = malloc( MAXRANDOMNAMELEN );
-               GenRandomName(opt->smbName);
-       } else {
-               /* username and domain for logon session is not necessarily the same as
-                  username and domain passed into network provider. */
-               PSECURITY_LOGON_SESSION_DATA plsd;
-               char lsaUsername[MAX_USERNAME_LENGTH];
-               char lsaDomain[MAX_DOMAIN_LENGTH];
-               size_t len, tlen;
+        GenRandomName(opt->smbName);
+    } else {
+        /* username and domain for logon session is not necessarily the same as
+           username and domain passed into network provider. */
+        PSECURITY_LOGON_SESSION_DATA plsd;
+        char lsaUsername[MAX_USERNAME_LENGTH];
+        char lsaDomain[MAX_DOMAIN_LENGTH];
+        size_t len, tlen;
 
         LsaGetLogonSessionData(lpLogonId, &plsd);
         
-               UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
-               UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
-
-               DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
-
-               if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
-                       len = tlen;
-               else
-                       goto bad_strings;
-
-               if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
-                       len += tlen;
-               else
-                       goto bad_strings;
-
-               len += 2;
-
-               opt->smbName = malloc(len);
-
-               StringCbCopy(opt->smbName, len, lsaDomain);
-               StringCbCat(opt->smbName, len, "\\");
-               StringCbCat(opt->smbName, len, lsaUsername);
-
-               strlwr(opt->smbName);
-
-bad_strings:
-               LsaFreeReturnBuffer(plsd);
-       }
-
-       DebugEvent("Looking up logon script");
-       /* Logon script */
-       /* First find out where the key is */
-       hkTemp = NULL;
-       rv = ~ERROR_SUCCESS;
-       dwType = 0;
-       if(hkDom)
-           rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
-       if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
-               hkTemp = hkDom;
-               DebugEvent("Located logon script in hkDom");
-       }
-       else if(hkDoms)
-           rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
-       if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
-               hkTemp = hkDoms;
-               DebugEvent("Located logon script in hkDoms");
-       }
-       /* Note that the LogonScript in the NP key is only used if we are doing high security. */
-       else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
-           rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
-       if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
-               hkTemp = hkNp;
-               DebugEvent("Located logon script in hkNp");
-       }
-
-       if(hkTemp) {
-               WCHAR *regscript        = NULL;
-               WCHAR *regexscript      = NULL;
-               WCHAR *regexuscript     = NULL;
-               WCHAR *wuname           = NULL;
-               HRESULT hr;
-
-               size_t len;
-               
-               StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
-               len ++;
+        UnicodeStringToANSI(plsd->UserName, lsaUsername, MAX_USERNAME_LENGTH);
+        UnicodeStringToANSI(plsd->LogonDomain, lsaDomain, MAX_DOMAIN_LENGTH);
+
+        DebugEvent("PLSD username[%s] domain[%s]",lsaUsername,lsaDomain);
+
+        if(SUCCEEDED(StringCbLength(lsaUsername, MAX_USERNAME_LENGTH, &tlen)))
+            len = tlen;
+        else
+            goto bad_strings;
+
+        if(SUCCEEDED(StringCbLength(lsaDomain, MAX_DOMAIN_LENGTH, &tlen)))
+            len += tlen;
+        else
+            goto bad_strings;
+
+        len += 2;
 
-               wuname = malloc(len * sizeof(WCHAR));
-               MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,len*sizeof(WCHAR));
+        opt->smbName = malloc(len);
 
-               DebugEvent("Username is set for [%S]", wuname);
+        StringCbCopy(opt->smbName, len, lsaDomain);
+        StringCbCat(opt->smbName, len, "\\");
+        StringCbCat(opt->smbName, len, lsaUsername);
+
+        strlwr(opt->smbName);
+
+      bad_strings:
+        LsaFreeReturnBuffer(plsd);
+    }
+
+    DebugEvent("Looking up logon script");
+    /* Logon script */
+    /* First find out where the key is */
+    hkTemp = NULL;
+    rv = ~ERROR_SUCCESS;
+    dwType = 0;
+    if(hkDom)
+        rv = RegQueryValueExW(hkDom, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
+    if(rv == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
+        hkTemp = hkDom;
+        DebugEvent("Located logon script in hkDom");
+    }
+    else if(hkDoms)
+        rv = RegQueryValueExW(hkDoms, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
+    if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
+        hkTemp = hkDoms;
+        DebugEvent("Located logon script in hkDoms");
+    }
+    /* Note that the LogonScript in the NP key is only used if we are doing high security. */
+    else if(hkNp && ISHIGHSECURITY(opt->LogonOption))
+        rv = RegQueryValueExW(hkNp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, NULL, &dwSize);
+    if(rv == ERROR_SUCCESS && !hkTemp && (dwType == REG_SZ || dwType == REG_EXPAND_SZ)) {
+        hkTemp = hkNp;
+        DebugEvent("Located logon script in hkNp");
+    }
 
-               /* dwSize still has the size of the required buffer in bytes. */
+    if(hkTemp) {
+        WCHAR *regscript       = NULL;
+        WCHAR *regexscript     = NULL;
+        WCHAR *regexuscript    = NULL;
+        WCHAR *wuname          = NULL;
+        HRESULT hr;
+
+        size_t len;
+
+        StringCbLength(opt->smbName, MAX_USERNAME_LENGTH, &len);
+        len ++;
+
+        wuname = malloc(len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP,0,opt->smbName,-1,wuname,len*sizeof(WCHAR));
+
+        DebugEvent("Username is set for [%S]", wuname);
+
+        /* dwSize still has the size of the required buffer in bytes. */
         regscript = malloc(dwSize);
-               rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
-               if(rv != ERROR_SUCCESS) {/* what the ..? */
-                       DebugEvent("Can't look up logon script [%d]",rv);
-                       goto doneLogonScript;
-               }
-               
-               DebugEvent("Found logon script [%S]", regscript);
-
-               if(dwType == REG_EXPAND_SZ) {
-                       DWORD dwReq;
-
-                       dwSize += MAX_PATH * sizeof(WCHAR);  /* make room for environment expansion. */
-                       regexscript = malloc(dwSize);
-                       dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
-                       free(regscript);
-                       regscript = regexscript;
-                       regexscript = NULL;
-                       if(dwReq > (dwSize / sizeof(WCHAR))) {
-                               DebugEvent("Overflow while expanding environment strings.");
-                               goto doneLogonScript;
-                       }
-               }
-
-               DebugEvent("After expanding env strings [%S]", regscript);
-
-               if(wcsstr(regscript, L"%s")) {
-               dwSize += len * sizeof(WCHAR); /* make room for username expansion */
-                       regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
-                       hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
-               } else {
-                       regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
-                       hr = StringCbCopyW(regexuscript, dwSize, regscript);
-               }
-
-               DebugEvent("After expanding username [%S]", regexuscript);
-
-               if(hr == S_OK)
-                       opt->logonScript = regexuscript;
-               else
-                       LocalFree(regexuscript);
-
-doneLogonScript:
-               if(wuname) free(wuname);
-               if(regscript) free(regscript);
-               if(regexscript) free(regexscript);
-       }
-
-cleanup:
-       if(hkNp) RegCloseKey(hkNp);
-       if(hkDom) RegCloseKey(hkDom);
-       if(hkDoms) RegCloseKey(hkDoms);
-       if(hkParm) RegCloseKey(hkParm);
-}
+        rv = RegQueryValueExW(hkTemp, REG_CLIENT_LOGON_SCRIPT_PARMW, 0, &dwType, (LPBYTE) regscript, &dwSize);
+        if(rv != ERROR_SUCCESS) {/* what the ..? */
+            DebugEvent("Can't look up logon script [%d]",rv);
+            goto doneLogonScript;
+        }
+
+        DebugEvent("Found logon script [%S]", regscript);
+
+        if(dwType == REG_EXPAND_SZ) {
+            DWORD dwReq;
+
+            dwSize += MAX_PATH * sizeof(WCHAR);  /* make room for environment expansion. */
+            regexscript = malloc(dwSize);
+            dwReq = ExpandEnvironmentStringsW(regscript, regexscript, dwSize / sizeof(WCHAR));
+            free(regscript);
+            regscript = regexscript;
+            regexscript = NULL;
+            if(dwReq > (dwSize / sizeof(WCHAR))) {
+                DebugEvent("Overflow while expanding environment strings.");
+                goto doneLogonScript;
+            }
+        }
+
+        DebugEvent("After expanding env strings [%S]", regscript);
+
+        if(wcsstr(regscript, L"%s")) {
+            dwSize += len * sizeof(WCHAR); /* make room for username expansion */
+            regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
+            hr = StringCbPrintfW(regexuscript, dwSize, regscript, wuname);
+        } else {
+            regexuscript = (WCHAR *) LocalAlloc(LMEM_FIXED, dwSize);
+            hr = StringCbCopyW(regexuscript, dwSize, regscript);
+        }
+
+        DebugEvent("After expanding username [%S]", regexuscript);
+
+        if(hr == S_OK)
+            opt->logonScript = regexuscript;
+        else
+            LocalFree(regexuscript);
+
+      doneLogonScript:
+        if(wuname) free(wuname);
+        if(regscript) free(regscript);
+        if(regexscript) free(regexscript);
+    }
+
+    DebugEvent("Looking up TheseCells");
+    /* Logon script */
+    /* First find out where the key is */
+    hkTemp = NULL;
+    rv = ~ERROR_SUCCESS;
+    dwType = 0;
+    if (hkDom)
+        rv = RegQueryValueEx(hkDom, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
+    if (rv == ERROR_SUCCESS && dwType == REG_MULTI_SZ) {
+        hkTemp = hkDom;
+        DebugEvent("Located TheseCells in hkDom");
+    } else if (hkDoms)
+        rv = RegQueryValueEx(hkDoms, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
+    if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
+        hkTemp = hkDoms;
+        DebugEvent("Located TheseCells in hkDoms");
+    } else if (hkNp)
+        rv = RegQueryValueEx(hkNp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, NULL, &dwSize);
+    if (rv == ERROR_SUCCESS && !hkTemp && dwType == REG_MULTI_SZ) {
+        hkTemp = hkNp;
+        DebugEvent("Located TheseCells in hkNp");
+    }
+
+    if (hkTemp) {
+        CHAR * thesecells;
+
+        /* dwSize still has the size of the required buffer in bytes. */
+        thesecells = malloc(dwSize);
+        rv = RegQueryValueEx(hkTemp, REG_CLIENT_THESE_CELLS_PARM, 0, &dwType, (LPBYTE) thesecells, &dwSize);
+        if(rv != ERROR_SUCCESS) {/* what the ..? */
+            DebugEvent("Can't look up TheseCells [%d]",rv);
+            goto doneTheseCells;
+        }
+
+        DebugEvent("Found TheseCells [%s]", thesecells);
+        opt->theseCells = thesecells;
+
+      doneTheseCells:;
+    }
+
+  cleanup:
+    if(hkNp) RegCloseKey(hkNp);
+    if(hkDom) RegCloseKey(hkDom);
+    if(hkDoms) RegCloseKey(hkDoms);
+    if(hkParm) RegCloseKey(hkParm);
+}       
 
 #undef LOOKUPKEYCHAIN
 
@@ -487,22 +594,22 @@ cleanup:
    the contents of *cell in case of failure. *cell is assumed to be
    at least cellLen chars */
 DWORD GetFileCellName(char * path, char * cell, size_t cellLen) {
-       struct ViceIoctl blob;
-       char tcell[MAX_PATH];
-       DWORD code;
+    struct ViceIoctl blob;
+    char tcell[MAX_PATH];
+    DWORD code;
 
-       blob.in_size = 0;
-       blob.out_size = MAX_PATH;
-       blob.out = tcell;
+    blob.in_size = 0;
+    blob.out_size = MAX_PATH;
+    blob.out = tcell;
 
-       code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
+    code = pioctl(path, VIOC_FILE_CELL_NAME, &blob, 1);
 
-       if(!code) {
-               strncpy(cell, tcell, cellLen);
-               cell[cellLen - 1] = '\0';
-       }
-       return code;
-}
+    if(!code) {
+        strncpy(cell, tcell, cellLen);
+        cell[cellLen - 1] = '\0';
+    }
+    return code;
+}       
 
 
 static BOOL
@@ -526,8 +633,8 @@ UnicodeStringToANSI(UNICODE_STRING uInputString, LPSTR lpszOutputString, int nOu
         lpszOutputString[min(uInputString.Length/2,nOutStringLen-1)] = '\0';
         return TRUE;
     }
-       else
-               lpszOutputString[0] = '\0';
+    else
+        lpszOutputString[0] = '\0';
     return FALSE;
 }  // UnicodeStringToANSI
 
@@ -541,182 +648,219 @@ DWORD APIENTRY NPLogonNotify(
        LPVOID StationHandle,
        LPWSTR *lpLogonScript)
 {
-       char uname[MAX_USERNAME_LENGTH]="";
-       char password[MAX_PASSWORD_LENGTH]="";
-       char logonDomain[MAX_DOMAIN_LENGTH]="";
-       char cell[256]="<non-integrated logon>";
-       char homePath[MAX_PATH]="";
+    char uname[MAX_USERNAME_LENGTH]="";
+    char password[MAX_PASSWORD_LENGTH]="";
+    char logonDomain[MAX_DOMAIN_LENGTH]="";
+    char cell[256]="<non-integrated logon>";
+    char homePath[MAX_PATH]="";
+    char szLogonId[128] = "";
+
+    MSV1_0_INTERACTIVE_LOGON *IL;
+
+    DWORD code, code2;
 
-       MSV1_0_INTERACTIVE_LOGON *IL;
+    int pw_exp;
+    char *reason;
+    char *ctemp;
 
-       DWORD code;
+    BOOLEAN interactive;
+    BOOLEAN flag;
+    DWORD LSPtype, LSPsize;
+    HKEY NPKey;
 
-       int pw_exp;
-       char *reason;
-       char *ctemp;
+    HWND hwndOwner = (HWND)StationHandle;
 
-       BOOLEAN interactive;
-       BOOLEAN flag;
-       DWORD LSPtype, LSPsize;
-       HKEY NPKey;
+    BOOLEAN afsWillAutoStart;
 
-       HWND hwndOwner = (HWND)StationHandle;
+    BOOLEAN lowercased_name = TRUE;
 
-       BOOLEAN afsWillAutoStart;
+    LogonOptions_t opt; /* domain specific logon options */
+    int retryInterval;
+    int sleepInterval;
 
-    BOOLEAN uppercased_name = TRUE;
+    (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
+                         0, KEY_QUERY_VALUE, &NPKey);
+    LSPsize=sizeof(TraceOption);
+    RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
+                     &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
+
+    RegCloseKey (NPKey);
 
-       LogonOptions_t opt; /* domain specific logon options */
-       int retryInterval;
-       int sleepInterval;
+    DebugEvent("NPLogonNotify - LoginId(%d,%d)", lpLogonId->HighPart, lpLogonId->LowPart);
 
     /* Make sure the AFS Libraries are initialized */
     AfsLogonInit();
 
     /* Initialize Logon Script to none */
-       *lpLogonScript=NULL;
+    *lpLogonScript=NULL;
     
-       /* TODO: We should check the value of lpAuthentInfoType before assuming that it is
-                MSV1_0_INTERACTIVE_LOGON though for our purposes KERB_INTERACTIVE_LOGON is
-                        co-incidentally equivalent. */
-       IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
+    /* MSV1_0_INTERACTIVE_LOGON and KERB_INTERACTIVE_LOGON are equivalent for
+     * our purposes */
+
+    if ( wcscmp(lpAuthentInfoType,L"MSV1_0:Interactive") && 
+         wcscmp(lpAuthentInfoType,L"Kerberos:Interactive") )
+    {
+        DebugEvent("Unsupported Authentication Info Type: %S",
+                   lpAuthentInfoType);
+        return 0;
+    }
 
-       /* Are we interactive? */
-       interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
+    IL = (MSV1_0_INTERACTIVE_LOGON *) lpAuthentInfo;
 
-       /* Convert from Unicode to ANSI */
+    /* Are we interactive? */
+    interactive = (wcscmp(lpStationName, L"WinSta0") == 0);
 
-       /*TODO: Use SecureZeroMemory to erase passwords */
-       UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
-       UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
-       UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
+    /* Convert from Unicode to ANSI */
 
-       /* Make sure AD-DOMANS sent from login that is sent to us is striped */
+    /*TODO: Use SecureZeroMemory to erase passwords */
+    UnicodeStringToANSI(IL->UserName, uname, MAX_USERNAME_LENGTH);
+    UnicodeStringToANSI(IL->Password, password, MAX_PASSWORD_LENGTH);
+    UnicodeStringToANSI(IL->LogonDomainName, logonDomain, MAX_DOMAIN_LENGTH);
+
+    /* Make sure AD-DOMANS sent from login that is sent to us is striped */
     ctemp = strchr(uname, '@');
     if (ctemp) *ctemp = 0;
 
-    /* is the name all uppercase? */
+    /* is the name all lowercase? */
     for ( ctemp = uname; *ctemp ; ctemp++) {
-        if ( islower(*ctemp) ) {
-            uppercased_name = FALSE;
+        if ( !islower(*ctemp) ) {
+            lowercased_name = FALSE;
             break;
         }
     }
 
-       (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
-                        0, KEY_QUERY_VALUE, &NPKey);
-       LSPsize=sizeof(TraceOption);
-       RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
-                     &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
-
-       RegCloseKey (NPKey);
+    /*
+     * Get Logon options
+     */
 
-       /*
-        * Get Logon options
-        */
+    GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
+    retryInterval = opt.retryInterval;
+    sleepInterval = opt.sleepInterval;
+    *lpLogonScript = opt.logonScript;
 
-       GetDomainLogonOptions( lpLogonId, uname, logonDomain, &opt );
-       retryInterval = opt.retryInterval;
-       sleepInterval = opt.sleepInterval;
-       *lpLogonScript = opt.logonScript;
+    if (retryInterval < sleepInterval)
+        sleepInterval = retryInterval;
 
-       DebugEvent("Got logon script: %S",opt.logonScript);
+    DebugEvent("Got logon script: %S",opt.logonScript);
 
-       afsWillAutoStart = AFSWillAutoStart();
+    afsWillAutoStart = AFSWillAutoStart();
 
-       DebugEvent("LogonOption[%x], Service AutoStart[%d]",
+    DebugEvent("LogonOption[%x], Service AutoStart[%d]",
                 opt.LogonOption,afsWillAutoStart);
     
     /* Check for zero length password if integrated logon*/
-       if ( ISLOGONINTEGRATED(opt.LogonOption) )  {
+    if ( ISLOGONINTEGRATED(opt.LogonOption) )  {
         if ( password[0] == 0 ) {
             DebugEvent("Password is the empty string");
             code = GT_PW_NULL;
             reason = "zero length password is illegal";
             code=0;
-        }
+        }       
 
         /* Get cell name if doing integrated logon.  
-                  We might overwrite this if we are logging into an AD realm and we find out that
-                  the user's home dir is in some other cell. */
+           We might overwrite this if we are logging into an AD realm and we find out that
+           the user's home dir is in some other cell. */
         DebugEvent("About to call cm_GetRootCellName(%s)",cell);
-               code = cm_GetRootCellName(cell);
-               if (code < 0) { 
+        code = cm_GetRootCellName(cell);
+        if (code < 0) { 
             DebugEvent("Unable to obtain Root Cell");
-                       code = KTC_NOCELL;
-                       reason = "unknown cell";
-                       code=0;
-               } else {
+            code = KTC_NOCELL;
+            reason = "unknown cell";
+            code=0;
+        } else {
             DebugEvent("Cell is %s",cell);
-        }
+        }       
 
-               /* We get the user's home directory path, if applicable, though we can't lookup the
-                  cell right away because the client service may not have started yet. This call
-                  also sets the AD_REALM flag in opt.flags if applicable. */
-               if(ISREMOTE(opt.flags)) {
+        /* We get the user's home directory path, if applicable, though we can't lookup the
+           cell right away because the client service may not have started yet. This call
+           also sets the AD_REALM flag in opt.flags if applicable. */
+        if (ISREMOTE(opt.flags)) {
             DebugEvent("Is Remote");
-                       GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
-        }
+            GetAdHomePath(homePath,MAX_PATH,lpLogonId,&opt);
+        }       
     }
 
     /* loop until AFS is started. */
-    while (TRUE) {
-        DebugEvent("while(TRUE) LogonOption[%x], Service AutoStart[%d]",
+    while (IsServiceRunning() || IsServiceStartPending()) {
+        DebugEvent("while(autostart) LogonOption[%x], Service AutoStart[%d]",
                     opt.LogonOption,afsWillAutoStart);
 
-        if(ISADREALM(opt.flags)) {
-                       code = GetFileCellName(homePath,cell,256);
-                       if(!code) {
-                               DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
-                       }
-                       /* Don't bail out if GetFileCellName failed.
-                        * The home dir may not be in AFS after all. 
-                        */
-               } else
-               code=0;
+        if (ISADREALM(opt.flags)) {
+            code = GetFileCellName(homePath,cell,256);
+            if (!code) {
+                DebugEvent("profile path [%s] is in cell [%s]",homePath,cell);
+            }
+            /* Don't bail out if GetFileCellName failed.
+             * The home dir may not be in AFS after all. 
+             */
+        } else
+            code=0;
                
         /* if Integrated Logon  */
         if (ISLOGONINTEGRATED(opt.LogonOption))
-               {                       
-                       if ( KFW_is_available() ) {
+        {                      
+            if ( KFW_is_available() ) {
                 code = KFW_AFS_get_cred(uname, cell, password, 0, opt.smbName, &reason);
-                               DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",uname,opt.smbName,cell,code);
-                       }
-                       else {
+                DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",uname,opt.smbName,cell,code);
+                if (code == 0 && opt.theseCells) { 
+                    char * principal, *p;
+
+                    principal = (char *)malloc(strlen(uname) + strlen(cell) + 2);
+                    if ( principal ) {
+                        strcpy(principal, uname);
+                        p = principal + strlen(uname);
+                        *p++ = '@';
+                        strcpy(p, cell);
+                        for ( ;*p; p++) {
+                            *p = toupper(*p);
+                        }
+
+                        p = opt.theseCells;
+                        while ( *p ) {
+                            code2 = KFW_AFS_get_cred(principal, p, 0, 0, opt.smbName, &reason);
+                            DebugEvent("KFW_AFS_get_cred  uname=[%s] smbname=[%s] cell=[%s] code=[%d]",
+                                        principal,opt.smbName,p,code2);
+                            p += strlen(p) + 1;
+                        }
+                        
+                        free(principal);
+                    }
+                }
+            } else {
                 code = ka_UserAuthenticateGeneral2(KA_USERAUTH_VERSION+KA_USERAUTH_AUTHENT_LOGON,
-                                                uname, "", cell, password, opt.smbName, 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 ) {
+                                                    uname, "", cell, password, opt.smbName, 0, &pw_exp, 0,
+                                                    &reason);
+                DebugEvent("AFS AfsLogon - (INTEGRATED only)ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s]",
+                            code,uname,cell);
+            }       
+            if ( code && code != KTC_NOCM && code != KTC_NOCMRPC && !lowercased_name ) {
                 for ( ctemp = uname; *ctemp ; ctemp++) {
                     *ctemp = tolower(*ctemp);
                 }
-                uppercased_name = FALSE;
-                continue;
+                lowercased_name = TRUE;
+                goto sleeping;
             }
-               }
-               else {  
+
+            /* is service started yet?*/
+
+            /* 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. */
+            if (code != KTC_NOCM && code != KTC_NOCMRPC)
+                break;
+        }
+        else {  
             /*JUST check to see if its running*/
-                   if (IsServiceRunning())
+            if (IsServiceRunning())
                 break;
-                   code = KTC_NOCM;
-                   if (!afsWillAutoStart)
+            if (!IsServiceStartPending()) {
+                code = KTC_NOCMRPC;
+                reason = "AFS Service start failed";
                 break;
-               }
-
-               /* is service started yet?*/
-        DebugEvent("AFS AfsLogon - ka_UserAuthenticateGeneral2","Code[%x] uname[%s] Cell[%s]",
-                   code,uname,cell);
-
-               /* 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. */
-               if (code != KTC_NOCM && code != KTC_NOCMRPC || !afsWillAutoStart)
-                       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
@@ -725,39 +869,42 @@ DWORD APIENTRY NPLogonNotify(
             reason = "AFS not running";
             if (!interactive || opt.failSilently)
                 break;
-                       flag = MessageBox(hwndOwner,
+            flag = MessageBox(hwndOwner,
                                "AFS is still starting.  Retry?",
                                "AFS Logon",
                                MB_ICONQUESTION | MB_RETRYCANCEL);
-                       if (flag == IDCANCEL)
+            if (flag == IDCANCEL)
                 break;
 
             /* Wait just a little while and try again */
-            retryInterval = sleepInterval = DEFAULT_SLEEP_INTERVAL;
+            retryInterval = opt.retryInterval;
         }
 
-        if (retryInterval < sleepInterval)
-                       sleepInterval = retryInterval;
-
-               Sleep(sleepInterval * 1000);
-
+      sleeping:
+        Sleep(sleepInterval * 1000);
         retryInterval -= sleepInterval;
     }
 
     DebugEvent("while loop exited");
-    /* remove any kerberos 5 tickets currently held by the SYSTEM account */
-    if ( KFW_is_available() )
-        KFW_AFS_destroy_tickets_for_cell(cell);
+    /* remove any kerberos 5 tickets currently held by the SYSTEM account
+     * for this user 
+     */
+    if ( KFW_is_available() ) {
+        sprintf(szLogonId,"%d.%d",lpLogonId->HighPart, lpLogonId->LowPart);
+        KFW_AFS_copy_cache_to_system_file(uname, szLogonId);
+
+        KFW_AFS_destroy_tickets_for_principal(uname);
+    }
 
-       if (code) {
+    if (code) {
         char msg[128];
         HANDLE h;
         char *ptbuf[1];
 
-               StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
+        StringCbPrintf(msg, sizeof(msg), "Integrated login failed: %s", reason);
 
-               if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
-                       MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
+        if (ISLOGONINTEGRATED(opt.LogonOption) && interactive && !opt.failSilently)
+            MessageBox(hwndOwner, msg, "AFS Logon", MB_OK);
 
         h = RegisterEventSource(NULL, AFS_LOGON_EVENT_NAME);
         ptbuf[0] = msg;
@@ -766,24 +913,24 @@ DWORD APIENTRY NPLogonNotify(
         DeregisterEventSource(h);
            
         code = MapAuthError(code);
-               SetLastError(code);
-
-               if (ISLOGONINTEGRATED(opt.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;
+        SetLastError(code);
 
-               }
-       }
+        if (ISLOGONINTEGRATED(opt.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(opt.smbName) free(opt.smbName);
+    if (opt.theseCells) free(opt.theseCells);
+    if (opt.smbName) free(opt.smbName);
 
-       DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
-       return code;
-}
+    DebugEvent("AFS AfsLogon - Exit","Return Code[%x]",code);
+    return code;
+}       
 
 DWORD APIENTRY NPPasswordChangeNotify(
        LPCWSTR lpAuthentInfoType,
@@ -797,8 +944,8 @@ DWORD APIENTRY NPPasswordChangeNotify(
     /* Make sure the AFS Libraries are initialized */
     AfsLogonInit();
 
-       DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
-       return 0;
+    DebugEvent0("AFS AfsLogon - NPPasswordChangeNotify");
+    return 0;
 }
 
 #include <userenv.h>
@@ -837,35 +984,111 @@ typedef struct _WLX_NOTIFICATION_INFO {
 
 VOID AFS_Startup_Event( PWLX_NOTIFICATION_INFO pInfo )
 {
-       DWORD LSPtype, LSPsize;
-       HKEY NPKey;
+    DWORD LSPtype, LSPsize;
+    HKEY NPKey;
 
     /* Make sure the AFS Libraries are initialized */
     AfsLogonInit();
 
-    (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_CLIENT_PARMS_KEY,
+    (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
                         0, KEY_QUERY_VALUE, &NPKey);
-       LSPsize=sizeof(TraceOption);
-       RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
+    LSPsize=sizeof(TraceOption);
+    RegQueryValueEx(NPKey, REG_CLIENT_TRACE_OPTION_PARM, NULL,
                      &LSPtype, (LPBYTE)&TraceOption, &LSPsize);
 
-       RegCloseKey (NPKey);
+    RegCloseKey (NPKey);
     DebugEvent0("AFS_Startup_Event");
 }
 
 VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
 {
     DWORD code;
-    TCHAR profileDir[256] = TEXT("");
-    DWORD  len = 256;
+    TCHAR profileDir[1024] = TEXT("");
+    DWORD  len = 1024;
+    PTOKEN_USER  tokenUser = NULL;
+    DWORD  retLen;
+    DWORD LSPtype, LSPsize;
+    HKEY NPKey;
+    DWORD LogoffPreserveTokens = 0;
+
+    /* Make sure the AFS Libraries are initialized */
+    AfsLogonInit();
+
+    DebugEvent0("AFS_Logoff_Event - Start");
+
+    (void) RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_CLT_SVC_PARAM_SUBKEY,
+                         0, KEY_QUERY_VALUE, &NPKey);
+    LSPsize=sizeof(LogoffPreserveTokens);
+    RegQueryValueEx(NPKey, REG_CLIENT_LOGOFF_TOKENS_PARM, NULL,
+                     &LSPtype, (LPBYTE)&LogoffPreserveTokens, &LSPsize);
+    RegCloseKey (NPKey);
+
+    if (LogoffPreserveTokens) {
+        if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
+        {
+            if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER ) {
+                tokenUser = (PTOKEN_USER) LocalAlloc(LPTR, retLen);
+
+                if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
+                {
+                    DebugEvent("AFS_Logoff_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
+                }
+            }
+        }
+
+        /* We can't use pInfo->Domain for the domain since in the cross realm case 
+         * this is source domain and not the destination domain.
+         */
+        if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
+            WCHAR Domain[64]=L"";
+            GetLocalShortDomain(Domain, sizeof(Domain));
+            if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
+                if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
+                    GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
+            }
+        }
+
+        if (strlen(profileDir)) {
+            DebugEvent("AFS_Logoff_Event - Profile Directory: %s", profileDir);
+            if (!IsPathInAfs(profileDir)) {
+                if (code = ktc_ForgetAllTokens())
+                    DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
+                else
+                    DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
+            } else {
+                DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
+            }
+        } else {
+            DebugEvent0("AFS_Logoff_Event - Unable to load profile");
+        }
+
+        if ( tokenUser )
+            LocalFree(tokenUser);
+    }
+
+    DebugEvent0("AFS_Logoff_Event - End");
+}   
+
+VOID AFS_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
+{
+    TCHAR profileDir[1024] = TEXT("");
+    DWORD  len = 1024;
     PTOKEN_USER  tokenUser = NULL;
     DWORD  retLen;
-    HANDLE hToken;
+    WCHAR szUserW[128] = L"";
+    char  szUserA[128] = "";
+    char  szClient[MAX_PATH];
+    char szPath[MAX_PATH] = "";
+    NETRESOURCE nr;
+    DWORD res;
+    DWORD dwSize;
 
     /* Make sure the AFS Libraries are initialized */
     AfsLogonInit();
 
-    DebugEvent0("AFS_Logoff_Event - Starting");
+    DebugEvent0("AFS_Logon_Event - Start");
+
+    DebugEvent("AFS_Logon_Event Process ID: %d",GetCurrentProcessId());
 
     if (!GetTokenInformation(pInfo->hToken, TokenUser, NULL, 0, &retLen))
     {
@@ -874,7 +1097,7 @@ VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
 
             if (!GetTokenInformation(pInfo->hToken, TokenUser, tokenUser, retLen, &retLen))
             {
-                DebugEvent("GetTokenInformation failed: GLE = %lX", GetLastError());
+                DebugEvent("AFS_Logon_Event - GetTokenInformation failed: GLE = %lX", GetLastError());
             }
         }
     }
@@ -885,25 +1108,161 @@ VOID AFS_Logoff_Event( PWLX_NOTIFICATION_INFO pInfo )
     if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, pInfo->Domain)) {
         WCHAR Domain[64]=L"";
         GetLocalShortDomain(Domain, sizeof(Domain));
-        if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain))
-            GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
+        if (QueryAdHomePathFromSid( profileDir, sizeof(profileDir), tokenUser->User.Sid, Domain)) {
+            if (NetUserGetProfilePath(pInfo->Domain, pInfo->UserName, profileDir, len))
+                GetUserProfileDirectory(pInfo->hToken, profileDir, &len);
+        }
     }
     
     if (strlen(profileDir)) {
-        DebugEvent("Profile Directory: %s", profileDir);
-        if (!IsPathInAfs(profileDir)) {
-            if (code = ktc_ForgetAllTokens())
-                DebugEvent("AFS_Logoff_Event - ForgetAllTokens failed [%lX]",code);
-            else
-                DebugEvent0("AFS_Logoff_Event - ForgetAllTokens succeeded");
-        } else {
-            DebugEvent0("AFS_Logoff_Event - Tokens left in place; profile in AFS");
-        }
+        DebugEvent("AFS_Logon_Event - Profile Directory: %s", profileDir);
     } else {
-        DebugEvent0("AFS_Logoff_Event - Unable to load profile");
+        DebugEvent0("AFS_Logon_Event - Unable to load profile");
     }
 
+    dwSize = sizeof(szUserA);
+    if (!KFW_AFS_get_lsa_principal(szUserA, &dwSize)) {
+        StringCbPrintfW(szUserW, sizeof(szUserW), L"%s\\%s", pInfo->Domain, pInfo->UserName);
+        WideCharToMultiByte(CP_ACP, 0, szUserW, -1, szUserA, MAX_PATH, NULL, NULL);
+    }
+
+    if (szUserA[0])
+    {
+        lana_GetNetbiosName(szClient, LANA_NETBIOS_NAME_FULL);
+        StringCbPrintf(szPath, sizeof(szPath), "\\\\%s", szClient);
+
+        DebugEvent("AFS_Logon_Event - Logon Name: %s", szUserA);
+
+        memset (&nr, 0x00, sizeof(NETRESOURCE));
+        nr.dwType=RESOURCETYPE_DISK;
+        nr.lpLocalName=0;
+        nr.lpRemoteName=szPath;
+        res = WNetAddConnection2(&nr,NULL,szUserA,0);
+        if (res)
+            DebugEvent("AFS_Logon_Event - WNetAddConnection2(%s,%s) failed: 0x%X",
+                        szPath, szUserA,res);
+        else
+            DebugEvent0("AFS_Logon_Event - WNetAddConnection2() succeeded");
+    } else 
+        DebugEvent("AFS_Logon_Event - User name conversion failed: GLE = 0x%X",GetLastError());
+
     if ( tokenUser )
         LocalFree(tokenUser);
-}   
+
+    DebugEvent0("AFS_Logon_Event - End");
+}
+
+static BOOL
+GetSecurityLogonSessionData(HANDLE hToken, PSECURITY_LOGON_SESSION_DATA * ppSessionData)
+{
+    NTSTATUS Status = 0;
+    HANDLE  TokenHandle;
+    TOKEN_STATISTICS Stats;
+    DWORD   ReqLen;
+    BOOL    Success;
+
+    if (!ppSessionData)
+        return FALSE;
+    *ppSessionData = NULL;
+
+#if 0
+    Success = OpenProcessToken( HANDLE GetCurrentProcess(), TOKEN_QUERY, &TokenHandle );
+    if ( !Success )
+        return FALSE;
+#endif
+
+    Success = GetTokenInformation( hToken, TokenStatistics, &Stats, sizeof(TOKEN_STATISTICS), &ReqLen );
+#if 0
+    CloseHandle( TokenHandle );
+#endif
+    if ( !Success )
+        return FALSE;
+
+    Status = LsaGetLogonSessionData( &Stats.AuthenticationId, ppSessionData );
+    if ( FAILED(Status) || !ppSessionData )
+        return FALSE;
+
+    return TRUE;
+}
+
+VOID KFW_Logon_Event( PWLX_NOTIFICATION_INFO pInfo )
+{
+    DWORD code;
+
+    WCHAR szUserW[128] = L"";
+    char  szUserA[128] = "";
+    char  szClient[MAX_PATH];
+    char szPath[MAX_PATH] = "";
+    char szLogonId[128] = "";
+    NETRESOURCE nr;
+    DWORD res;
+    DWORD gle;
+    DWORD dwSize;
+    DWORD dwDisp;
+    DWORD dwType;
+    DWORD count;
+    VOID * ticketData;
+    char filename[256];
+    char commandline[512];
+    STARTUPINFO startupinfo;
+    PROCESS_INFORMATION procinfo;
+
+    LUID LogonId = {0, 0};
+    PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
+
+    HKEY hKey1 = NULL, hKey2 = NULL;
+
+    /* Make sure the KFW Libraries are initialized */
+    AfsLogonInit();
+
+    DebugEvent0("KFW_Logon_Event - Start");
+
+    GetSecurityLogonSessionData( pInfo->hToken, &pLogonSessionData );
+
+    if ( pLogonSessionData ) {
+        LogonId = pLogonSessionData->LogonId;
+        DebugEvent("KFW_Logon_Event - LogonId(%d,%d)", LogonId.HighPart, LogonId.LowPart);
+
+        sprintf(szLogonId,"%d.%d",LogonId.HighPart, LogonId.LowPart);
+        LsaFreeReturnBuffer( pLogonSessionData );
+    } else {
+        DebugEvent0("KFW_Logon_Event - Unable to determine LogonId");
+        return;
+    }
+
+    count = GetEnvironmentVariable("TEMP", filename, sizeof(filename));
+    if ( count > sizeof(filename) || count == 0 ) {
+        GetWindowsDirectory(filename, sizeof(filename));
+    }
+
+    if ( strlen(filename) + strlen(szLogonId) + 2 <= sizeof(filename) ) {
+        strcat(filename, "\\");
+        strcat(filename, szLogonId);    
+
+        sprintf(commandline, "afscpcc.exe \"%s\"", filename);
+
+        GetStartupInfo(&startupinfo);
+        if (CreateProcessAsUser( pInfo->hToken,
+                             "afscpcc.exe",
+                             commandline,
+                             NULL,
+                             NULL,
+                             FALSE,
+                             CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS,
+                             NULL,
+                             NULL,
+                             &startupinfo,
+                             &procinfo)) 
+        {
+            WaitForSingleObject(procinfo.hProcess, 30000);
+
+            CloseHandle(procinfo.hThread);
+            CloseHandle(procinfo.hProcess);
+        }
+    }
+
+    DeleteFile(filename);
+
+    DebugEvent0("KFW_Logon_Event - End");
+}