//+------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1996 - 1997
//
//  File:    csmain.cxx
//
//  Contents:    Main cxx for Directory Class Access Implementation
//              Local Server.
//
//  Author:    DebiM
//
//-------------------------------------------------------------------------

#include "cstore.hxx"


//
// Link list pointer for Class Containers Seen
//
CLASSCONTAINER *gpContainerHead = NULL;

//
// Link list pointer for User Profiles Seen
//
USERPROFILE *gpUserHead = NULL;

//
// Class Factory Objects
//
long ObjectCount = 0;

CAppContainerCF   *   pCF = NULL;
CClassAccessCF      *   pCSAccessCF = NULL;
extern CClassContainerCF  *g_pCF;

//IClassAccess        *   gpClassAccess = NULL;

//
// Critical Section for Sid List
//
CRITICAL_SECTION ClassStoreBindList;

//
//---------------------------------------------------------------------
// Following are used for Supporting Test Scenarios thru FlushSidCache.
WCHAR pwszDebugPath [_MAX_PATH];
BOOL  fDebugPath = FALSE;
//---------------------------------------------------------------------


//
// ResetClassStoreState
// --------------------
//
//  Synopsis:       Calling this will close all Class Containers 
//                  in use and also cleanup state information about all user sids
//                  that have initiated Class Store requests. 
//                  This routine is called at during shut down of 
//                  Class Store Server. 
//
//  Arguments:      None
//
//  Returns:        None
//

void ResetClassStoreState()
//
// This routine is called at during shut down of Class Store Server
//
{
    //
    // Check if there are any outstanding open Class Stores
    //

    CLASSCONTAINER *pCS = gpContainerHead, *pCSTemp;

    while (pCS != NULL)
    {
        if (pCS->gpClassStore)
        {
            (pCS->gpClassStore)->Release();
            pCS->gpClassStore = NULL;
            CSDbgPrint(("Found open container and closed.\n"));
        }

        if (pCS->pszClassStorePath)
        {
            CoTaskMemFree (pCS->pszClassStorePath);
            pCS->pszClassStorePath = NULL;
        }
        pCSTemp = pCS->pNextClassStore;
        CoTaskMemFree (pCS);
        pCS = pCSTemp;
    }

    gpContainerHead = NULL;


    USERPROFILE *pUser = gpUserHead, *pUserTemp;
    while (pUser != NULL)
    {
        if (pUser->pCachedSid)
            CoTaskMemFree (pUser->pCachedSid);

        if (pUser->pUserStoreList)
            CoTaskMemFree (pUser->pUserStoreList);

        pUser->cUserStoreCount = 0;

        pUserTemp = pUser->pNextUser;
        CoTaskMemFree (pUser);
        pUser = pUserTemp;
    }
    
    gpUserHead = NULL;

    CSDbgPrint(("ResetClassStoreState completed.\n"));
}

//
// ResetUserState
// --------------
//
//  Synopsis:       Calling this will flush all state information 
//                  about all user sids that have initiated 
//                  Class Store requests. 
//                  
//                  It is called by the special test entry point 
//                  FlushSidCache.
//
//  Arguments:      LPOLESTR pwszNewPath as the new Class Store path for All
//
//  Returns:        None
//


void ResetUserState(LPOLESTR pwszNewPath)
//
{
    USERPROFILE *pUser = gpUserHead, *pUserTemp;
    while (pUser != NULL)
    {
        if (pUser->pCachedSid)
            CoTaskMemFree (pUser->pCachedSid);

        pUser->cUserStoreCount = 0;

        pUserTemp = pUser->pNextUser;
        CoTaskMemFree (pUser);
        pUser = pUserTemp;
    }
    
    gpUserHead = NULL;
    wcscpy (&pwszDebugPath[0], pwszNewPath);
    fDebugPath = TRUE;

    CSDbgPrint(("ResetUserState completed.\n"));
}

//
// Uninitialize
// -------------
//
//  Synopsis:       Class Store Server Uninitialization.
//                  Disconnects from all Class Containers in use.
//                  Flushes out all State information using ResetClassStoreState.
//                  Unregisters Server registrations etc..
//
//  Arguments:      None
//
//  Returns:        None
//

void Uninitialize()
{
    //
    // Cleanup all open containers
    //

    //ResetClassStoreState();
    //
    // release the Class Factory objects
    //
    if (pCF)
        pCF->Release();
    if (pCSAccessCF)
        pCSAccessCF->Release();

    if (g_pCF)
        g_pCF->Release();
    //
    // get rid of the critical section
    //

    DeleteCriticalSection(&ClassStoreBindList);

}


//
// FlushSidCache
// -------------
//
//  Synopsis:       Supported for Testing Only. Not exposed thru any header.
//                  Calling this empties out Class Store Cache.
//
//  Arguments:      pwszNewPath
//
//  Returns:        S_OK
//

HRESULT FlushSidCache (LPOLESTR pwszNewPath)
{

    EnterCriticalSection (&ClassStoreBindList);

    ResetUserState(pwszNewPath);

    LeaveCriticalSection (&ClassStoreBindList);

    return S_OK;
}

//+---------------------------------------------------------------------------
//
//  Function:   InitializeClassStore
//
//  History:    7-25-96   DebiM   Created
//
//  This entry point is called at DLL attach
//----------------------------------------------------------------------------
BOOL InitializeClassStore(BOOL fInit)
{
    HRESULT     hr;
    BOOL        bStatus;
    
    ObjectCount = 1;
    /*
    ACL *       pAcl;
    DWORD       AclSize;
    SECURITY_DESCRIPTOR * pSD;

    SID     LocalSystemSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID };
    SID     InteractiveSid = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_INTERACTIVE_RID };


    // Started manually.  Don't go away.
    AclSize = sizeof(ACL) + 2 * sizeof(ACCESS_ALLOWED_ACE) + 2 * sizeof(SID);

    pSD = (SECURITY_DESCRIPTOR *)
          PrivMemAlloc( sizeof(SECURITY_DESCRIPTOR) + 2 * sizeof(SID) + AclSize );

    if ( ! pSD )
        return FALSE;

    bStatus = TRUE;
    pAcl = (ACL *) ( ((BYTE *)&pSD[1]) + 2 * sizeof(SID) );

    if ( ! InitializeAcl( pAcl, AclSize, ACL_REVISION2 ) ||
         ! AddAccessAllowedAce( pAcl, ACL_REVISION2, COM_RIGHTS_EXECUTE, &LocalSystemSid ) ||
         ! AddAccessAllowedAce( pAcl, ACL_REVISION2, COM_RIGHTS_EXECUTE, &InteractiveSid ) )
        bStatus = FALSE;

    if ( ! InitializeSecurityDescriptor( pSD, SECURITY_DESCRIPTOR_REVISION ) ||
         ! SetSecurityDescriptorDacl( pSD, TRUE, pAcl, FALSE ) ||
         ! SetSecurityDescriptorGroup( pSD, &LocalSystemSid, FALSE ) ||
         ! SetSecurityDescriptorOwner( pSD, &LocalSystemSid, FALSE ) )
        bStatus = FALSE;

    if ( bStatus )
    {
        hr = CoInitializeSecurity(
                    pSD,
                    -1,
                    NULL,
                    NULL,
                    RPC_C_AUTHN_LEVEL_CONNECT,
                    RPC_C_IMP_LEVEL_IDENTIFY,
                    NULL,
                    EOAC_NONE,
                    NULL );
    }

    PrivMemFree( pSD );

    if ( ! bStatus || (hr != S_OK) )
    {
        CSDbgPrint(("Class Store: Couldn't initialize security\n"));
    }
    */


    /*
    if (fInit)
    {
        hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
        if (hr)
            CSDbgPrint(("RPCSS : CoInitialize returned 0x%x.\n", hr));
    }
    */

    pCF = new CAppContainerCF();
    pCSAccessCF = new CClassAccessCF();

    NTSTATUS status = RtlInitializeCriticalSection(&ClassStoreBindList);

/*    hr = pCSAccessCF->CreateInstance( NULL, IID_IClassAccess, (void **) &gpClassAccess );

    if ( hr != S_OK )
    {
        CSDbgPrint(("RPCSS : Counldn't create ClassAccess 0x%x\n", hr));
        return FALSE;
    }
*/    
    g_pCF = new CClassContainerCF;

    if (!pCF || !pCSAccessCF || !g_pCF || !NT_SUCCESS(status))
    {
        ASSERT(FALSE);
    	goto fail;
    }

    return TRUE;

fail:
    if (pCF)
        delete pCF;
    if (pCSAccessCF)
        delete pCSAccessCF;
    if (g_pCF)
    	{
    	delete g_pCF;
    	g_pCF = NULL;
    	}
    
    return FALSE;

}
/*

//  Globals
HINSTANCE g_hInst = NULL;

   

//+---------------------------------------------------------------
//
//  Function:   DllGetClassObject
//
//  Synopsis:   Standard DLL entrypoint for locating class factories
//
//----------------------------------------------------------------

STDAPI
DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID FAR* ppv)
{
    HRESULT         hr;
    size_t          i;

    if (IsEqualCLSID(clsid, CLSID_ClassAccess))
    {
        return pCSAccessCF->QueryInterface(iid, ppv);
    }

    *ppv = NULL;

    return E_NOINTERFACE;
}

//+---------------------------------------------------------------
//
//  Function:   DllCanUnloadNow
//
//  Synopsis:   Standard DLL entrypoint to determine if DLL can be unloaded
//
//---------------------------------------------------------------

STDAPI
DllCanUnloadNow(void)
{
    HRESULT hr;

    hr = S_FALSE;

    //
    // BugBug 
    //
    if (ulObjectCount > 0)
        hr = S_FALSE;
    else
        hr = S_OK;
    return hr;
}


//+---------------------------------------------------------------
//
//  Function:   LibMain
//
//  Synopsis:   Standard DLL initialization entrypoint
//
//---------------------------------------------------------------

EXTERN_C BOOL _CRTAPI1
LibMain(HINSTANCE hInst, ULONG ulReason, LPVOID pvReserved)
{
    HRESULT     hr;
    DWORD cbSize = _MAX_PATH;
    WCHAR wszUserName [_MAX_PATH];

    switch (ulReason)
    {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls(hInst);
        g_hInst = hInst;
        InitializeClassStore();
        break;


    case DLL_PROCESS_DETACH:
        Uninitialize();
        break;

    default:
        break;
    }

    return TRUE;
}

//+---------------------------------------------------------------------------
//
//  Function:   DllMain
//
//  Synopsis:   entry point for NT
//
//----------------------------------------------------------------------------
BOOL
DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
{
    return LibMain((HINSTANCE)hDll, dwReason, lpReserved);
}
*/

//+-------------------------------------------------------------------------
//
//  Function:   CsGetClassAccess
//
//  Synopsis:   Returns an instantiated interface to the Class Store
//              Co-ordinator object in Rpcss.
//
//  Arguments:  [ppIClassAccess] - where to put class access interface pointer
//
//  Returns:    S_OK - Got a Class Access Successfully
//              E_FAIL
//
//--------------------------------------------------------------------------

STDAPI CsGetClassAccess(
    IClassAccess     **     ppIClassAccess)
{
    HRESULT     hr;
    *ppIClassAccess = NULL;

    hr = pCSAccessCF->CreateInstance( NULL, 
        IID_IClassAccess, 
        (void **)ppIClassAccess);

    return hr;

}

//+-------------------------------------------------------------------
//
// CsEnumApps (DebiM 11/7/97)
//
// Returns an enumerator for packages in the Class Store (s).
// The enumerator works across all class stores in the calling users profile.
//
//
// This is used by:
//    - Add/Remove programs to select Corporate Apps
//    - winlogon to obtain the list of assigned apps
//
// Arguments:
//  [in]
//        pszPackageName    :   Optional Wildcard string for PackageName
//        pLastUsn          :   Optional Time Stamp for new packages
//        pCategory         :   Optional CategoryId
//        dwAppFlags        :   Per APPINFO_xxx in objbase.h
//  [out]
//        ppIEnumPackage    :   Returned Interface Pointer
//
// Returns :
//      S_OK or E_NO_CLASSSTORE
//
//--------------------------------------------------------------------
STDAPI
CsEnumApps(
        LPOLESTR        pszPackageName,    // Wildcard string for PackageName
        GUID            *pCategory,        // CategoryId
        ULONGLONG       *pLastUsn,         // Time Stamp for new packages
        DWORD           dwAppFlags,        // Per APPINFO_xxx in objbase.h
        IEnumPackage    **ppIEnumPackage   // Returned Interface Pointer
        )
{
    HRESULT         hr;
    IClassAccess  * pIClassAccess = NULL;

    *ppIEnumPackage = NULL;

    //
    // Get an IClassAccess 
    //
    hr = CsGetClassAccess(&pIClassAccess);
    if (!SUCCEEDED(hr))
        return hr;

    //
    // Get the enumerator
    //
    hr = pIClassAccess->EnumPackages (
        pszPackageName,
        pCategory,
        pLastUsn,
        dwAppFlags,
        ppIEnumPackage
        );

    pIClassAccess->Release();
    return hr;
}

void
GetDefaultPlatform(CSPLATFORM *pPlatform)
{
    OSVERSIONINFO VersionInformation;

    VersionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&VersionInformation);

    pPlatform->dwPlatformId = VersionInformation.dwPlatformId;
    pPlatform->dwVersionHi = VersionInformation.dwMajorVersion;
    pPlatform->dwVersionLo = VersionInformation.dwMinorVersion;
    pPlatform->dwProcessorArch = DEFAULT_ARCHITECTURE;
}

//+-------------------------------------------------------------------
//
// CsGetAppInfo
//
// Looks up the given class specification in the DS.  If an application for
// this class specification is found, then the application details are returned.
//
// Arguments :
//
//--------------------------------------------------------------------
STDAPI
CsGetAppInfo(
         uCLSSPEC       *   pClassSpec,            // Class Spec (GUID/Ext/MIME)
         QUERYCONTEXT   *   pQueryContext,
         INSTALLINFO    *   pInstallInfo
        )
{
    HRESULT         hr;
    QUERYCONTEXT    QueryContext;
    IClassAccess  * pIClassAccess = NULL;
    
    if ( pQueryContext )
    {
        QueryContext = *pQueryContext;
    }
    else
    {
        QueryContext.dwContext = CLSCTX_ALL;
        GetDefaultPlatform( &QueryContext.Platform );
        QueryContext.Locale = GetThreadLocale();
        QueryContext.dwVersionHi = (DWORD) -1;
        QueryContext.dwVersionLo = (DWORD) -1;
    }

    //
    // Get an IClassAccess 
    //
    hr = CsGetClassAccess(&pIClassAccess);
    if (!SUCCEEDED(hr))
        return hr;
    hr = pIClassAccess->GetAppInfo(pClassSpec, &QueryContext, pInstallInfo );
    pIClassAccess->Release();
    return hr;
}