Index: base/system/services/rpcserver.c =================================================================== --- base/system/services/rpcserver.c (révision 56781) +++ base/system/services/rpcserver.c (copie de travail) @@ -15,8 +15,26 @@ #define NDEBUG #include +#include + /* GLOBALS *****************************************************************/ +/* + * Structure describing a user database lock. + */ +#define LOCK_TAG 0x4C697041 /* 'ApiL' */ + +typedef struct _SC_LOCK_STRUCT +{ + DWORD Tag; /* Must be LOCK_TAG */ + LPWSTR DatabaseName; + DWORD TimeWhenLocked; /* Number of seconds since 1970 */ + PSID LockOwnerSid; /* It is NULL if SC Manager grabbed the lock */ +} SC_LOCK_STRUCT, *PSC_LOCK_STRUCT; + +PSC_LOCK_STRUCT SCActiveDatabaseLock = NULL; + + #define MANAGER_TAG 0x72674D68 /* 'hMgr' */ #define SERVICE_TAG 0x63765368 /* 'hSvc' */ @@ -1298,6 +1316,58 @@ } +static DWORD +ScmLockDatabase(IN BOOL IsServiceController, // TRUE if locked by the Service Control Manager, FALSE otherwise. + IN LPWSTR DatabaseName, + OUT LPSC_RPC_LOCK lpLock) +{ + DWORD bufSize = 0; + + *lpLock = NULL; + + if (SCActiveDatabaseLock != NULL) + { + return ERROR_SERVICE_DATABASE_LOCKED; + } + else + { + /* + * Allocate a new lock for the database. + */ + bufSize = sizeof(SC_LOCK_STRUCT) + (DatabaseName ? (wcslen(DatabaseName) + 1) * sizeof(WCHAR) : 0); + + if (!IsServiceController) + { + /* FIXME: bufSize += RtlLengthSid(UserSid <-- to be retrieved); */ + } + + SCActiveDatabaseLock = (PSC_LOCK_STRUCT)HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + bufSize); + if (SCActiveDatabaseLock == NULL) + { + return ERROR_NOT_ENOUGH_MEMORY; + } + + SCActiveDatabaseLock->Tag = LOCK_TAG; + + if (DatabaseName) + { + SCActiveDatabaseLock->DatabaseName = (LPWSTR)(SCActiveDatabaseLock + 1); + wcscpy(SCActiveDatabaseLock->DatabaseName, DatabaseName); + } + + SCActiveDatabaseLock->TimeWhenLocked = (DWORD)time(NULL); + /* FIXME: Retrieve the owner SID. Use IsServiceController. */ + SCActiveDatabaseLock->LockOwnerSid = (PSID)NULL; + + *lpLock = SCActiveDatabaseLock; + + return ERROR_SUCCESS; + } +} + + /* Function 3 */ DWORD RLockServiceDatabase( SC_RPC_HANDLE hSCManager, @@ -1307,7 +1377,8 @@ DPRINT("RLockServiceDatabase() called\n"); - *lpLock = 0; + // assert(lpLock); + *lpLock = NULL; hMgr = ScmGetServiceManagerFromHandle(hSCManager); if (hMgr == NULL) @@ -1320,12 +1391,9 @@ SC_MANAGER_LOCK)) return ERROR_ACCESS_DENIED; -// return ScmLockDatabase(0, hMgr->0xC, hLock); + DPRINT("RLockServiceDatabase() done\n"); - /* FIXME: Lock the database */ - *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */ - - return ERROR_SUCCESS; + return ScmLockDatabase(FALSE, hMgr->DatabaseName, lpLock); } @@ -1706,7 +1774,33 @@ DWORD RUnlockServiceDatabase( LPSC_RPC_LOCK Lock) { - UNIMPLEMENTED; + PSC_LOCK_STRUCT apiLock; + + DPRINT("RUnlockServiceDatabase() called\n"); + + if (Lock == NULL) + return ERROR_INVALID_SERVICE_LOCK; + + apiLock = *(PSC_LOCK_STRUCT*)Lock; + + if (apiLock->Tag != LOCK_TAG) + return ERROR_INVALID_SERVICE_LOCK; + + /* Release the lock handle */ + if ( (apiLock == SCActiveDatabaseLock) && + (SCActiveDatabaseLock != NULL) ) + { + HeapFree(GetProcessHeap(), 0, SCActiveDatabaseLock); + SCActiveDatabaseLock = NULL; + *Lock = NULL; + } + else + { + return ERROR_INVALID_SERVICE_LOCK; + } + + DPRINT("RUnlockServiceDatabase() done\n"); + return ERROR_SUCCESS; } @@ -2857,12 +2951,58 @@ /* Function 18 */ DWORD RQueryServiceLockStatusW( SC_RPC_HANDLE hSCManager, - LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus, + LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus, DWORD cbBufSize, LPBOUNDED_DWORD_4K pcbBytesNeeded) { - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; + LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSW)lpBuf; + PMANAGER_HANDLE hMgr; + DWORD dwRequiredSize; + + if (!lpLockStatus || !pcbBytesNeeded) + return ERROR_INVALID_PARAMETER; + + hMgr = ScmGetServiceManagerFromHandle(hSCManager); + if (hMgr == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess, + SC_MANAGER_QUERY_LOCK_STATUS)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + /* HACK: we need to compute instead the real length of the owner name */ + dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR); + *pcbBytesNeeded = dwRequiredSize; + + if (cbBufSize < dwRequiredSize) + return ERROR_INSUFFICIENT_BUFFER; + + if (SCActiveDatabaseLock) + { + lpLockStatus->fIsLocked = TRUE; + + /* FIXME: Retrieve the owner name. */ + lpLockStatus->lpLockOwner = NULL; + + lpLockStatus->dwLockDuration = (DWORD)time(NULL) - SCActiveDatabaseLock->TimeWhenLocked; + } + else + { + lpLockStatus->fIsLocked = FALSE; + + wcscpy((LPWSTR)(lpLockStatus + 1), L""); + lpLockStatus->lpLockOwner = (LPWSTR)(ULONG_PTR)sizeof(QUERY_SERVICE_LOCK_STATUSW); + + lpLockStatus->dwLockDuration = 0; + } + + return ERROR_SUCCESS; } @@ -4090,12 +4230,58 @@ /* Function 30 */ DWORD RQueryServiceLockStatusA( SC_RPC_HANDLE hSCManager, - LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus, + LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus, DWORD cbBufSize, LPBOUNDED_DWORD_4K pcbBytesNeeded) { - UNIMPLEMENTED; - return ERROR_CALL_NOT_IMPLEMENTED; + LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSA)lpBuf; + PMANAGER_HANDLE hMgr; + DWORD dwRequiredSize; + + if (!lpLockStatus || !pcbBytesNeeded) + return ERROR_INVALID_PARAMETER; + + hMgr = ScmGetServiceManagerFromHandle(hSCManager); + if (hMgr == NULL) + { + DPRINT1("Invalid service manager handle!\n"); + return ERROR_INVALID_HANDLE; + } + + if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess, + SC_MANAGER_QUERY_LOCK_STATUS)) + { + DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess); + return ERROR_ACCESS_DENIED; + } + + /* HACK: we need to compute instead the real length of the owner name */ + dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR); + *pcbBytesNeeded = dwRequiredSize; + + if (cbBufSize < dwRequiredSize) + return ERROR_INSUFFICIENT_BUFFER; + + if (SCActiveDatabaseLock) + { + lpLockStatus->fIsLocked = TRUE; + + /* FIXME: Retrieve the owner name. */ + lpLockStatus->lpLockOwner = NULL; + + lpLockStatus->dwLockDuration = (DWORD)time(NULL) - SCActiveDatabaseLock->TimeWhenLocked; + } + else + { + lpLockStatus->fIsLocked = FALSE; + + strcpy((LPSTR)(lpLockStatus + 1), ""); + lpLockStatus->lpLockOwner = (LPSTR)(ULONG_PTR)sizeof(QUERY_SERVICE_LOCK_STATUSA); + + lpLockStatus->dwLockDuration = 0; + } + + return ERROR_SUCCESS; } Index: dll/win32/advapi32/service/scm.c =================================================================== --- dll/win32/advapi32/service/scm.c (révision 56781) +++ dll/win32/advapi32/service/scm.c (copie de travail) @@ -2286,7 +2286,7 @@ { /* Call to services.exe using RPC */ dwError = RQueryServiceLockStatusA((SC_RPC_HANDLE)hSCManager, - lpStatusPtr, + (LPBYTE)lpStatusPtr, dwBufferSize, pcbBytesNeeded); } @@ -2348,7 +2348,7 @@ { /* Call to services.exe using RPC */ dwError = RQueryServiceLockStatusW((SC_RPC_HANDLE)hSCManager, - lpStatusPtr, + (LPBYTE)lpStatusPtr, dwBufferSize, pcbBytesNeeded); } Index: include/reactos/idl/svcctl.idl =================================================================== --- include/reactos/idl/svcctl.idl (révision 56781) +++ include/reactos/idl/svcctl.idl (copie de travail) @@ -443,7 +443,8 @@ /* Function 18 */ DWORD RQueryServiceLockStatusW( [in] SC_RPC_HANDLE hSCManager, - [out] LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus, + [out, size_is(cbBufSize)] LPBYTE lpLockStatus, + /* FIXME: should be [out] LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus, */ [in, range(0, 1024*4)] DWORD cbBufSize, [out] LPBOUNDED_DWORD_4K pcbBytesNeeded); @@ -555,7 +556,8 @@ /* Function 30 */ DWORD RQueryServiceLockStatusA( [in] SC_RPC_HANDLE hSCManager, - [out] LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus, + [out, size_is(cbBufSize)] LPBYTE lpLockStatus, + /* FIXME: should be [out] LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus, */ [in, range(0, 1024*4)] DWORD cbBufSize, [out] LPBOUNDED_DWORD_4K pcbBytesNeeded);