97 lines
4.2 KiB
C
97 lines
4.2 KiB
C
// Native service-manager control protocol. Names determine exported handle identity.
|
|
|
|
#pragma once
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <ntlite/port.h>
|
|
#include <ntlite/status.h>
|
|
|
|
#define NTL_SERVICE_CONTROL_VERSION 3u
|
|
#define NTL_SERVICE_CONTROL_READY 1u
|
|
#define NTL_SERVICE_CONTROL_STOP 2u
|
|
#define NTL_SERVICE_EXPORT_NAME_MAX 31u
|
|
|
|
// READY transfers one handle for each named entry in ExportNames. The entry at
|
|
// index i names the handle at transfer index i; its position has no semantic
|
|
// meaning. STOP transfers zero handles and carries only zeroed export names.
|
|
// Each message is wholly self-contained so the Port cannot retain user pointers.
|
|
typedef struct NTL_SERVICE_CONTROL_MESSAGE {
|
|
uint32_t Size;
|
|
uint32_t Version;
|
|
uint32_t Operation;
|
|
uint32_t ExportCount;
|
|
KSTATUS Status;
|
|
uint32_t Reserved[3];
|
|
char ExportNames[SYS_PORT_MAX_TRANSFER_HANDLES][NTL_SERVICE_EXPORT_NAME_MAX + 1u];
|
|
} NTL_SERVICE_CONTROL_MESSAGE;
|
|
|
|
// Accepts the deliberately restricted, case-sensitive capability-name grammar.
|
|
static inline bool NtlServiceExportNameValid(const char* name) {
|
|
if (!name || !name[0]) return false;
|
|
for (uint32_t i = 0; i <= NTL_SERVICE_EXPORT_NAME_MAX; ++i) {
|
|
char c = name[i];
|
|
if (!c) return i != 0;
|
|
if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
|
|
(c >= '0' && c <= '9') || c == '_' || c == '-' || c == '.'))
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Labels an already counted READY transfer without assigning authority to its name.
|
|
static inline bool NtlServiceControlNameExport(NTL_SERVICE_CONTROL_MESSAGE* message,
|
|
uint32_t index, const char* name) {
|
|
if (!message || message->Operation != NTL_SERVICE_CONTROL_READY ||
|
|
index >= message->ExportCount || index >= SYS_PORT_MAX_TRANSFER_HANDLES ||
|
|
!NtlServiceExportNameValid(name))
|
|
return false;
|
|
memset(message->ExportNames[index], 0, sizeof(message->ExportNames[index]));
|
|
size_t length = strlen(name);
|
|
memcpy(message->ExportNames[index], name, length);
|
|
return true;
|
|
}
|
|
|
|
// Validates wire size, exact transfer count, export names, and zeroed unused entries.
|
|
static inline bool NtlServiceControlValid(const NTL_SERVICE_CONTROL_MESSAGE* message,
|
|
uint32_t operation, uint32_t handleCount) {
|
|
if (!message || message->Size != sizeof(*message) ||
|
|
message->Version != NTL_SERVICE_CONTROL_VERSION || message->Operation != operation ||
|
|
(operation != NTL_SERVICE_CONTROL_READY && operation != NTL_SERVICE_CONTROL_STOP) ||
|
|
message->ExportCount != handleCount || handleCount > SYS_PORT_MAX_TRANSFER_HANDLES ||
|
|
message->Reserved[0] || message->Reserved[1] || message->Reserved[2])
|
|
return false;
|
|
if (operation == NTL_SERVICE_CONTROL_STOP &&
|
|
(handleCount != 0u || message->Status != NTLSTATUS_SUCCESS))
|
|
return false;
|
|
for (uint32_t i = 0; i < SYS_PORT_MAX_TRANSFER_HANDLES; ++i) {
|
|
const char* name = message->ExportNames[i];
|
|
if (i >= handleCount) {
|
|
for (uint32_t j = 0; j <= NTL_SERVICE_EXPORT_NAME_MAX; ++j)
|
|
if (name[j]) return false;
|
|
continue;
|
|
}
|
|
if (!NtlServiceExportNameValid(name)) return false;
|
|
// The complete fixed-size wire representation has one canonical encoding.
|
|
uint32_t end = 0;
|
|
while (name[end]) ++end;
|
|
for (uint32_t j = end + 1u; j <= NTL_SERVICE_EXPORT_NAME_MAX; ++j)
|
|
if (name[j]) return false;
|
|
for (uint32_t earlier = 0; earlier < i; ++earlier)
|
|
if (strcmp(name, message->ExportNames[earlier]) == 0) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Finds the transfer index for a validated named READY export.
|
|
static inline int32_t NtlServiceControlFindExport(const NTL_SERVICE_CONTROL_MESSAGE* message,
|
|
const char* name) {
|
|
if (!message || !NtlServiceExportNameValid(name) ||
|
|
message->ExportCount > SYS_PORT_MAX_TRANSFER_HANDLES)
|
|
return -1;
|
|
for (uint32_t i = 0; i < message->ExportCount; ++i)
|
|
if (strcmp(message->ExportNames[i], name) == 0) return (int32_t)i;
|
|
return -1;
|
|
}
|