/*++ Copyright (c) 1999 Microsoft Corporation Module Name: global.h Abstract: This file contains globals and prototypes for user mode webdav client. Author: Andy Herron (andyhe) 30-Mar-1999 Rohan Kumar [RohanK] 01-Sept-1999 Environment: User Mode - Win32 Revision History: --*/ #ifndef _DAVGLOBAL_H #define _DAVGLOBAL_H #pragma once #include #include #include #include "validc.h" // // If the following line is commented, the WinInet calls that are made will be // synchronous and we use the Win32 thread pool to do the management. If its // not commented, then we use WinInet asynchronously. // // #define DAV_USE_WININET_ASYNCHRONOUSLY 1 // // svcmain.c will #include this file with GLOBAL_DATA_ALLOCATE defined. // That will cause each of these variables to be allocated. // #ifdef GLOBAL_DATA_ALLOCATE #undef EXTERN #define EXTERN #define GLOBAL_DATA_ALLOCATED #undef INIT_GLOBAL #define INIT_GLOBAL(v) =v #else #define EXTERN extern #define INIT_GLOBAL(v) #endif #define DAV_MAXTHREADCOUNT_DEFAULT 6 #define DAV_THREADCOUNT_DEFAULT 2 // // Define all global variables here. // EXTERN HANDLE DavRedirDeviceHandle INIT_GLOBAL(INVALID_HANDLE_VALUE); EXTERN CRITICAL_SECTION g_DavServiceLock; EXTERN BOOLEAN g_DavServiceLockSet INIT_GLOBAL(FALSE); EXTERN HINSTANCE g_hinst; EXTERN BOOL g_RpcActive INIT_GLOBAL(FALSE); EXTERN BOOL g_RedirLoaded INIT_GLOBAL(FALSE); EXTERN BOOL g_registeredService INIT_GLOBAL(FALSE); EXTERN BOOL g_WorkersActive INIT_GLOBAL(FALSE); EXTERN SERVICE_STATUS_HANDLE g_hStatus; EXTERN SERVICE_STATUS g_status; EXTERN ULONG DavInitialThreadCount; EXTERN ULONG DavMaxThreadCount; EXTERN PUMRX_USERMODE_REFLECT_BLOCK DavReflectorHandle INIT_GLOBAL(NULL); EXTERN WSADATA g_wsaData; EXTERN BOOLEAN g_socketinit; EXTERN BOOL g_LUIDDeviceMapsEnabled; EXTERN UNICODE_STRING RedirDeviceName; // // This handle is set using InternetOpen function. The process passes this // handle to subsequent functions like InternetConnect. Its maintained as a // global to avoid creating such a handle on every call which goes to the // server. // extern HINTERNET IHandle; // // A synchronous version of the Internet handle. This is used to satisfy some // if the NP APIs without going to the kernel. // extern HINTERNET ISyncHandle; // // Dav Use Table. This table stores the "net use" connections made by the users // per LogonId. // extern DAV_USERS_OBJECT DavUseObject; // // Number of users logged on to the system. The Critical section below it // synchronizes the acces to this variable. // extern ULONG DavNumberOfLoggedOnUsers; extern CRITICAL_SECTION DavLoggedOnUsersLock; extern CRITICAL_SECTION DavPassportLock; // // The "wait hint time" told to the service control manager when the DAV // service is starting. // #define DAV_WAIT_HINT_TIME 60000 // 60 Seconds // // Error codes special to DAV. Defined in RFC 2518 (Section 10). Its interesting // to note that the value DAV_STATUS_INSUFFICIENT_STORAGE (below) has a higher // value than HTTP_STATUS_LAST defined in WinInet.h. So, this value (507) // becomes the highest possible return status from a Http/Dav server. // #define DAV_MULTI_STATUS 207 #define DAV_STATUS_UNPROCESSABLE_ENTITY 422 #define DAV_STATUS_LOCKED 423 #define DAV_STATUS_FAILED_DEPENDENCY 424 #define DAV_STATUS_INSUFFICIENT_STORAGE 507 // // The dummy share that is added when a user does a "net use * http://server". // We allow this since this implies mapping a drive to the root of the DAV // server. // #define DAV_DUMMY_SHARE L"DavWWWRoot" // // The different states of a server entry. // typedef enum _SERVER_ENTRY_STATES { // // Some thread is currently initializing this server entry. // ServerEntryInitializing = 0, // // The initialization was unsuccessful and this server is not being // considered a DAV server. // ServerEntryInitializationError, // // The server entry has been initializeed and is ready to use. // ServerEntryInitialized } SERVER_ENTRY_STATES; // // The Server Hash Table entry. // typedef struct _HASH_SERVER_ENTRY { // // Name. // PWCHAR ServerName; // // Server ID. This ID is sent up by the kernel and is unique per server. // ULONG ServerID; // // The state of the server entry. // SERVER_ENTRY_STATES ServerEntryState; // // This event is set by the thread which creates and initializes a server // after it has initialized it. This is to wake up any threads which could // have been waiting for the initialization to finish. // HANDLE ServerEventHandle; // // If the initialization was unsuccessful, the error status is filled in // this varriable. // ULONG ErrorStatus; // // Is it a HTTP server ? // BOOL isHttpServer; // // Does it support the DAV extensions ? // BOOL isDavServer; // // Is it the Microsoft IIS ? // BOOL isMSIIS; // // Is it an Office Web Server? // BOOL isOfficeServer; // // Is it a TAHOE Server? // BOOL isTahoeServer; // // Does it support PROPPATCH ? // BOOL fSupportsProppatch; // // If the creation of the SrvCall failed because the credentials were not // correct (in other words, the user was not authorized) then we set this // to TRUE. // BOOL credentialFailure; // // Pointer to the per user list. // LIST_ENTRY PerUserEntry; // // The next entry. // LIST_ENTRY ServerListEntry; // // We need to keep a reference count on this ServerEntry. // ULONG ServerEntryRefCount; // // Size of this entry including the server name. // ULONG EntrySize; // // The timer value used in the delayed SrvCall finalization. // time_t TimeValueInSec; // // This is set to TRUE if the worker thread tried to finalize this server // hash entry. If this server entry is moved from "to be finalized" list // to the hash table, this value is checked. If its TRUE, it implies that // the reference counts on the user entries were decremented by the worker // thread and have to be incremented back again. It also implies that the // state of the user entry was set to closing and has to be reset. // BOOL HasItBeenScavenged; BOOL CookieIsNotUsed; // // This should be the last field. // WCHAR StrBuffer[1]; } HASH_SERVER_ENTRY, *PHASH_SERVER_ENTRY; // // TimeValueInSec is set to this value if it should not be removed from the // Server hash table. // #define DONT_EXPIRE -1 // // Whenever we encounter a server that does not speak the DAV protocol in the // DavrDoesServerDoDav function, we add it to the NonDAVServerList. An entry // is kept on this list for ServerNotFoundCacheLifeTimeInSec (a global read // from the registry during service start-up). Before going on the network // to figure out whether a server does DAV, we look in the list to see if we // have already seen this server (which does not do DAV) and fail the call. // extern LIST_ENTRY NonDAVServerList; extern CRITICAL_SECTION NonDAVServerListLock; // // The ServerEntry that is created and added to the NonDAVServerList each time // we encounter a server that does not speak the DAV protocol in the // // typedef struct _NON_DAV_SERVER_ENTRY { LIST_ENTRY listEntry; // // The name of the server which does not speak WebDAV. // PWCHAR ServerName; // // The time of creation of this entry. // time_t TimeValueInSec; } NON_DAV_SERVER_ENTRY, *PNON_DAV_SERVER_ENTRY; // // The delay in sec that the user mode adds (to the finalization of the SrvCall) // after the kernel mode does the finalization of the SrvCall. // #define DAV_SERV_CACHE_VALUE L"ServerNotFoundCacheLifeTimeInSec" extern ULONG ServerNotFoundCacheLifeTimeInSec; // // Should we accept/claim the OfficeWebServers and TahoeWebServers? // #define DAV_ACCEPT_TAHOE_OFFICE_SERVERS L"AcceptOfficeAndTahoeServers" extern ULONG AcceptOfficeAndTahoeServers; // // Should we LOCK (using the DAV LOCK Verb) the file on the server on the // CreateFile path when needed? To know when exactly a LOCK is sent to the // server, look at the (LOCKing) comments in the davcreat.c file. // #define DAV_SUPPORT_LOCKING_OF_FILES L"SupportLocking" extern ULONG DavSupportLockingOfFiles; // // The maximum file size that is allowed by the WebDAV Redir. We keep a limit // on the file size to avoid being attacked by a rogue server. A rogue server // could keep on sending infinite amount of data which can cause the WebClient // service to use 100% of the CPU. // #define DAV_FILE_SIZE_LIMIT L"FileSizeLimitInBytes" extern ULONG DavFileSizeLimitInBytes; // // The maximum attributes size that is allowed by the WebDAV Redir. We keep a // limit on this size to avoid being attacked by a rogue server. A rogue server // could keep on sending infinite amount of data which can cause the WebClient // service to use 100% of the CPU. This attribute limit covers all the // PROPFIND and PROPPATCH responses. For PROPFINDs with Depth 1 we make the // limit a multiple of DavFileAttributesLimitInBytes (10 times). // #define DAV_ATTRIBUTES_SIZE_LIMIT L"FileAttributesLimitInBytes" extern ULONG DavFileAttributesLimitInBytes; // // The Global HashTable containing the HashServerEntries and the lock used while // accessing it. The server table has 512 entries because each entry is 8 bytes // and so the table size is 4096 bytes (1 page). // #define SERVER_TABLE_SIZE 512 #define MAX_NUMBER_OF_SERVER_ENTRIES_PER_HASH_ID (((DWORD)(-1))/SERVER_TABLE_SIZE) // // The hash table containing server entries. When a CreateSrvCall requests comes // up, this table is checked to see if the server entry exists. if it does not // a new entry is created and added to the list. // extern LIST_ENTRY ServerHashTable[SERVER_TABLE_SIZE]; // // This critical section synchronizes access to the ServerHashTable. // extern CRITICAL_SECTION HashServerEntryTableLock; // // This is a counter that gets incremented everytime a new server entry is // created in the hash table. This defines the unique server id for the entry. // The id values are never reused. // extern ULONG ServerIDCount; // // Mentioned below are the custom OFFICE and TAHOE headers which will be // returned in the response to a PROPFIND request. // extern WCHAR *DavTahoeCustomHeader; extern WCHAR *DavOfficeCustomHeader; // // This list contains the following types of server entries: // 1. The server entires for whom the SrvCall finalization has been received // from the kernel mode. // 2. Server entries which failed during the Creation of SrvCall (after the // memory was allocated for the entry) and, // This list is maintained for two reasons: // 1. To delay the finalization of the SrvCall in user mode. Instead of // finalizing these entries right away (after receiving the request from the // kernel), we keep them around for a certain time (say t sec). If a request // for creating a SrvCall for this server comes up again in these t sec, then // we just move this entry back to the ServerHashTable. This helps us in // avoiding network calls and, // 2. To do negative caching. If a machine (for which the CreateSrvCall request // came up) is not a DAV server, we maintain this info for a while (t sec). // If another SrvCall request for the same server comes up in this t sec, // we can return error without going to the net. This is what we mean by // negative caching. // A worker thread periodically goes over the list and checks the time each // entry has spent in the list. If the time exceeds a certain threshold (t sec // as defined above), it is removed from the list and finalized. The lock used // to synchronize access to this list is the same one used to aceess the // ServerHashEntry table. // extern LIST_ENTRY ToBeFinalizedServerEntries; // // The different states of a user entry. // typedef enum _USER_ENTRY_STATES { // // This user entry has been created, but not initialized. // UserEntryAllocated = 0, // // Some thread is currently initializing this entry. // UserEntryInitializing, // // The initialization was unsuccessful. // UserEntryInitializationError, // // The entry has been initialized and is ready to use. // UserEntryInitialized, // // The entry is going to be freed soon. If the entry is in this state, // no one should be using it. // UserEntryClosing } USER_ENTRY_STATES; // // The "Per User Entry" data structure. A list of such entries is maintained // per server entry in the server hash table (see below). // typedef struct _PER_USER_ENTRY { // // Unique logon/user ID for this session. // LUID LogonID; // // The server hash entry off which this user entry is hanging. // PHASH_SERVER_ENTRY ServerHashEntry; // // Pointer to the next "per user entry" for this server. // LIST_ENTRY UserEntry; // // The InternetConnect handle. // HINTERNET DavConnHandle; // // The state of this user entry. The thread that creates this user entry // sets its state to "UserEntryInitializing" before it initializes it. // This is done so that any other thread that comes in looking for this // entry when its in the middle of its initialization process can wait. // USER_ENTRY_STATES UserEntryState; // // This event is set by the thread which creates and initializes a user // after it has initialized it. This is to wake up any threads which could // have been waiting for the initialization to finish. // HANDLE UserEventHandle; // // The reference count value of this entry. This value is used in managing // the resource. // ULONG UserEntryRefCount; // // If the initialization was unsuccessful, the error status is filled in // this varriable. // ULONG ErrorStatus; // // The passport cookie for the this user/server pair. // PWCHAR Cookie; PWCHAR UserName; PWCHAR Password; DWORD BlockSizeInBytes; } PER_USER_ENTRY, *PPER_USER_ENTRY; #define PASSWORD_SEED 0x25 #include #include "debug.h" // // Function prototypes go here. // DWORD ReadDWord( HKEY KeyHandle, LPTSTR lpValueName, DWORD DefaultValue ); DWORD SetupRpcServer( VOID ); DWORD StopRpcServer( VOID ); VOID UpdateServiceStatus ( DWORD dwState ); NET_API_STATUS WsLoadDriver( IN LPWSTR DriverNameString ); NET_API_STATUS WsMapStatus( IN NTSTATUS NtStatus ); DWORD DavReportEventW( DWORD EventID, DWORD EventType, DWORD NumStrings, DWORD DataLength, LPWSTR *Strings, LPVOID Data ); NET_API_STATUS WsLoadRedir( VOID ); NET_API_STATUS WsUnloadRedir( VOID ); DWORD DavInitWorkerThreads( IN ULONG InitialThreadCount, IN ULONG MaxThreadCount ); DWORD DavTerminateWorkerThreads( VOID ); ULONG DavInit( VOID ); VOID DavClose( VOID ); ULONG DavHashTheServerName( PWCHAR ServerName ); BOOL DavIsThisServerInTheTable( IN PWCHAR ServerName, OUT PHASH_SERVER_ENTRY *ServerHashEntry ); BOOL DavIsServerInFinalizeList( IN PWCHAR ServerName, OUT PHASH_SERVER_ENTRY *ServerHashEntry, IN BOOL ReactivateIfExists ); VOID DavInitializeAndInsertTheServerEntry( IN OUT PHASH_SERVER_ENTRY ServerHashEntry, IN PWCHAR ServerName, IN ULONG EntrySize ); VOID DavFinalizeToBeFinalizedList( VOID ); DWORD DavPostWorkItem( LPTHREAD_START_ROUTINE Function, PDAV_USERMODE_WORKITEM DavContext ); ULONG InitializeTheSocketInterface( VOID ); NTSTATUS CleanupTheSocketInterface( VOID ); DWORD DavAsyncCreateSrvCall( PDAV_USERMODE_WORKITEM DavWorkItem, BOOLEAN CalledByCallBackThread ); VOID DavAsyncCreateSrvCallCompletion( PDAV_USERMODE_WORKITEM DavWorkItem ); DWORD DavAsyncCreate( PDAV_USERMODE_WORKITEM DavWorkItem, BOOLEAN CalledByCallBackThread ); VOID DavAsyncCreateCompletion( PDAV_USERMODE_WORKITEM DavWorkItem ); DWORD DavAsyncQueryDirectory( PDAV_USERMODE_WORKITEM DavWorkItem, BOOLEAN CalledByCallBackThread ); VOID DavAsyncQueryDirectoryCompletion( PDAV_USERMODE_WORKITEM DavWorkItem ); DWORD DavAsyncCreateVNetRoot( PDAV_USERMODE_WORKITEM DavWorkItem, BOOLEAN CalledByCallBackThread ); VOID DavAsyncCreateVNetRootCompletion( PDAV_USERMODE_WORKITEM DavWorkItem ); DWORD DavAsyncReName( PDAV_USERMODE_WORKITEM DavWorkItem, BOOLEAN CalledByCallBackThread ); VOID DavAsyncReNameCompletion( PDAV_USERMODE_WORKITEM DavWorkItem ); DWORD DavAsyncSetFileInformation( PDAV_USERMODE_WORKITEM DavWorkItem, BOOLEAN CalledByCallBackThread ); VOID DavAsyncSetFileInformationCompletion( PDAV_USERMODE_WORKITEM DavWorkItem ); DWORD DavAsyncClose( PDAV_USERMODE_WORKITEM DavWorkItem, BOOLEAN CalledByCallBackThread ); VOID DavAsyncCloseCompletion( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavQueryPassportCookie( IN HINTERNET RequestHandle, IN OUT PWCHAR *Cookie ); VOID DavDumpHttpResponseHeader( HINTERNET OpenHandle ); VOID DavDumpHttpResponseData( HINTERNET OpenHandle ); ULONG DavQueryAndParseResponse( HINTERNET DavOpenHandle ); ULONG DavQueryAndParseResponseEx( IN HINTERNET DavOpenHandle, OUT PULONG HttpResponseStatus OPTIONAL ); VOID DavRemoveDummyShareFromFileName( PWCHAR FileName ); ULONG DavMapHttpErrorToDosError( ULONG HttpResponseStatus ); // // The callback function used in asynchronous requests. // VOID _stdcall DavHandleAsyncResponse( HINTERNET IHandle, DWORD_PTR CallBackContext, DWORD InternetStatus, LPVOID StatusInformation, DWORD StatusInformationLength ); DWORD WINAPI DavCommonDispatch( LPVOID Context ); DWORD DavAsyncCommonStates( PDAV_USERMODE_WORKITEM DavWorkItem, BOOLEAN CalledByCallBackThread ); BOOL DavDoesUserEntryExist( IN PWCHAR ServerName, IN ULONG ServerID, IN PLUID LogonID, OUT PPER_USER_ENTRY *PerUserEntry, OUT PHASH_SERVER_ENTRY *ServerHashEntry ); BOOL DavFinalizePerUserEntry( PPER_USER_ENTRY *PUE ); ULONG DavFsSetTheDavCallBackContext( IN OUT PDAV_USERMODE_WORKITEM pDavWorkItem ); VOID DavFsFinalizeTheDavCallBackContext( IN PDAV_USERMODE_WORKITEM pDavWorkItem ); DWORD DavUnLockTheFileOnTheServer( IN PDAV_USERMODE_WORKITEM DavWorkItem ); // // Functions exposed to the usermode reflector library. // ULONG DavFsCreate( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavFsCreateSrvCall( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavFsCreateVNetRoot( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavFsFinalizeSrvCall( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavFsFinalizeVNetRoot( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavFsFinalizeFobx( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavFsQueryDirectory( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavFsQueryVolumeInformation( PDAV_USERMODE_WORKITEM DavWorkItem ); DWORD DavAsyncQueryVolumeInformation( PDAV_USERMODE_WORKITEM DavWorkItem, BOOLEAN CalledByCallBackThread ); VOID DavAsyncQueryVolumeInformationCompletion( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavFsReName( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavFsSetFileInformation( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavFsClose( PDAV_USERMODE_WORKITEM DavWorkItem ); ULONG DavFsLockRefresh( PDAV_USERMODE_WORKITEM DavWorkItem ); NTSTATUS DavMapErrorToNtStatus( DWORD dwWininetError ); NTSTATUS DavDosErrorToNtStatus( DWORD dwError ); VOID DavObtainServerProperties( PWCHAR lpInParseData, BOOL *lpfIsHttpServer, BOOL *lpfIsIIs, BOOL *lpfIsDavServer ); DWORD DavTestProppatch( PDAV_USERMODE_WORKITEM DavWorkItem, HINTERNET hDavConnect, LPWSTR lpPathName ); DWORD DavSetBasicInformation( PDAV_USERMODE_WORKITEM DavWorkItem, HINTERNET hDavConnect, LPWSTR PathName, BOOL fCreationTimeChanged, BOOL fLastAccessTimeChanged, BOOL fLastModifiedTimeChanged, BOOL fFileAttributesChanged, IN LARGE_INTEGER *lpCreationTime, IN LARGE_INTEGER *lpLastAccessTime, IN LARGE_INTEGER *lpLastModifiedTime, DWORD dwFileAttributes ); DWORD DavReportEventInEventLog( DWORD EventType, DWORD EventId, DWORD NumberOfStrings, PWCHAR *EventStrings ); DWORD DavFormatAndLogError( PDAV_USERMODE_WORKITEM DavWorkItem, DWORD Win32Status ); DWORD DavParseXmlResponse( HINTERNET DavOpenHandle, DAV_FILE_ATTRIBUTES *pDavFileAttributesIn, DWORD *pNumFileEntries ); DWORD DavAttachPassportCookie( PDAV_USERMODE_WORKITEM DavWorkItem, HINTERNET DavOpenHandle, PWCHAR *PassportCookie ); DWORD DavInternetSetOption( PDAV_USERMODE_WORKITEM DavWorkItem, HINTERNET DavOpenHandle ); #endif // DAVGLOBAL_H