93 lines
3.4 KiB
C
93 lines
3.4 KiB
C
// Kernel well-known system-service registry. This file intentionally owns only numeric service discovery.
|
|
|
|
#include <kernel/ke_system_service.h>
|
|
#include <kernel/ke_port.h>
|
|
#include <kernel/ke_spinlock.h>
|
|
#include <kernel/ob_object.h>
|
|
#include <ntlite/security.h>
|
|
|
|
static SPINLOCK gSystemServiceLock = SPINLOCK_INIT;
|
|
static PORT* gSystemServices[SYS_SERVICE_MAX + 1u];
|
|
|
|
// Returns whether one numeric service identifier is valid for the current ABI.
|
|
static bool KiSystemServiceIdValid(SYS_SERVICE_ID serviceId) {
|
|
return serviceId > SYS_SERVICE_INVALID && serviceId <= SYS_SERVICE_MAX;
|
|
}
|
|
|
|
// Returns the security claim that authorizes publication of one well-known service.
|
|
SYS_SERVICE_CLAIMS KeSystemServiceRequiredClaim(SYS_SERVICE_ID serviceId) {
|
|
switch (serviceId) {
|
|
case SYS_SERVICE_RESOURCE:
|
|
return SYS_SERVICE_CLAIM_RESOURCE;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Registers one weak listener reference without creating a string or pathname namespace.
|
|
KSTATUS KeSystemServiceRegister(SYS_SERVICE_ID serviceId, PORT* listener) {
|
|
if (!KiSystemServiceIdValid(serviceId) || !listener || !KePortIsListener(listener))
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
uintptr_t flags = KeAcquireSpinlock(&gSystemServiceLock);
|
|
if (gSystemServices[serviceId]) {
|
|
KeReleaseSpinlock(&gSystemServiceLock, flags);
|
|
return NTLSTATUS_ALREADY_EXISTS;
|
|
}
|
|
gSystemServices[serviceId] = listener;
|
|
KeReleaseSpinlock(&gSystemServiceLock, flags);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Removes one registration only when the caller still names the registered listener object.
|
|
KSTATUS KeSystemServiceUnregister(SYS_SERVICE_ID serviceId, PORT* listener) {
|
|
if (!KiSystemServiceIdValid(serviceId) || !listener || !KePortIsListener(listener))
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
uintptr_t flags = KeAcquireSpinlock(&gSystemServiceLock);
|
|
if (!gSystemServices[serviceId]) {
|
|
KeReleaseSpinlock(&gSystemServiceLock, flags);
|
|
return NTLSTATUS_NOT_FOUND;
|
|
}
|
|
if (gSystemServices[serviceId] != listener) {
|
|
KeReleaseSpinlock(&gSystemServiceLock, flags);
|
|
return NTLSTATUS_ACCESS_DENIED;
|
|
}
|
|
gSystemServices[serviceId] = (PORT*)0;
|
|
KeReleaseSpinlock(&gSystemServiceLock, flags);
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// References one currently registered listener for a connect operation.
|
|
KSTATUS KeSystemServiceReference(SYS_SERVICE_ID serviceId, PORT** listenerOut) {
|
|
if (!listenerOut)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
*listenerOut = (PORT*)0;
|
|
if (!KiSystemServiceIdValid(serviceId))
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
uintptr_t flags = KeAcquireSpinlock(&gSystemServiceLock);
|
|
PORT* listener = gSystemServices[serviceId];
|
|
if (!listener || !ObTryReferenceObject((OBJECT*)listener)) {
|
|
KeReleaseSpinlock(&gSystemServiceLock, flags);
|
|
return NTLSTATUS_NOT_FOUND;
|
|
}
|
|
KeReleaseSpinlock(&gSystemServiceLock, flags);
|
|
|
|
*listenerOut = listener;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Removes any weak registration whose listener is entering terminal object destruction.
|
|
void KeSystemServiceUnregisterListener(PORT* listener) {
|
|
if (!listener)
|
|
return;
|
|
|
|
uintptr_t flags = KeAcquireSpinlock(&gSystemServiceLock);
|
|
for (SYS_SERVICE_ID id = 1; id <= SYS_SERVICE_MAX; ++id) {
|
|
if (gSystemServices[id] == listener)
|
|
gSystemServices[id] = (PORT*)0;
|
|
}
|
|
KeReleaseSpinlock(&gSystemServiceLock, flags);
|
|
}
|