|
|
8b5736 |
/*********************************************************/
|
|
|
8b5736 |
/* toksvc: a framework-native token broker service */
|
|
|
d91fa0 |
/* Copyright (C) 2020 SysDeer Technologies, LLC */
|
|
|
8b5736 |
/* Released under GPLv2 and GPLv3; see COPYING.TOKSVC. */
|
|
|
8b5736 |
/*********************************************************/
|
|
|
8b5736 |
|
|
|
8b5736 |
#include <ntapi/ntapi.h>
|
|
|
8b5736 |
#include <stdio.h>
|
|
|
8b5736 |
#include <unistd.h>
|
|
|
8b5736 |
|
|
|
8b5736 |
#include <toksvc/toksvc.h>
|
|
|
8b5736 |
#include "toksvc_init_impl.h"
|
|
|
8b5736 |
#include "toksvc_driver_impl.h"
|
|
|
8b5736 |
#include "toksvc_dprintf_impl.h"
|
|
|
8b5736 |
#include "toksvc_nolibc_impl.h"
|
|
|
b27e56 |
#include "toksvc_log_impl.h"
|
|
|
8b5736 |
|
|
|
8b5736 |
#ifndef TOKS_DRIVER_FLAGS
|
|
|
8b5736 |
#define TOKS_DRIVER_FLAGS TOKS_DRIVER_VERBOSITY_ERRORS \
|
|
|
3e9813 |
| TOKS_DRIVER_DAEMON_ALWAYS \
|
|
|
8b5736 |
| TOKS_DRIVER_VERBOSITY_USAGE
|
|
|
8b5736 |
#endif
|
|
|
8b5736 |
|
|
|
8b5736 |
static const char vermsg[] = "%s%s%s (git://midipix.org/toksvc): "
|
|
|
8b5736 |
"version %s%d.%d.%d%s.\n"
|
|
|
8b5736 |
"[commit reference: %s%s%s]\n";
|
|
|
8b5736 |
|
|
|
8b5736 |
static const char * const toks_ver_color[6] = {
|
|
|
8b5736 |
"\x1b[1m\x1b[35m","\x1b[0m",
|
|
|
8b5736 |
"\x1b[1m\x1b[32m","\x1b[0m",
|
|
|
8b5736 |
"\x1b[1m\x1b[34m","\x1b[0m"
|
|
|
8b5736 |
};
|
|
|
8b5736 |
|
|
|
8b5736 |
static const char * const toks_ver_plain[6] = {
|
|
|
8b5736 |
"","",
|
|
|
8b5736 |
"","",
|
|
|
8b5736 |
"",""
|
|
|
8b5736 |
};
|
|
|
8b5736 |
|
|
|
8b5736 |
static ssize_t toks_version(struct toks_driver_ctx * dctx)
|
|
|
8b5736 |
{
|
|
|
8b5736 |
const struct toks_source_version * verinfo;
|
|
|
8b5736 |
const char * const * verclr;
|
|
|
8b5736 |
|
|
|
8b5736 |
verinfo = toks_source_version();
|
|
|
8b5736 |
verclr = isatty(STDOUT_FILENO) ? toks_ver_color : toks_ver_plain;
|
|
|
8b5736 |
|
|
|
8b5736 |
return toks_dprintf(
|
|
|
8b5736 |
STDOUT_FILENO,vermsg,
|
|
|
8b5736 |
verclr[0],dctx->program,verclr[1],
|
|
|
8b5736 |
verclr[2],verinfo->major,verinfo->minor,
|
|
|
8b5736 |
verinfo->revision,verclr[3],
|
|
|
8b5736 |
verclr[4],verinfo->commit,verclr[5]);
|
|
|
8b5736 |
}
|
|
|
8b5736 |
|
|
|
eb3ecd |
static ssize_t toks_output_service_info(const struct toks_service_info * svcinfo)
|
|
|
0b7161 |
{
|
|
|
0b7161 |
char guidstr[40];
|
|
|
0b7161 |
|
|
|
0b7161 |
toks_uuid_to_string(
|
|
|
0b7161 |
&svcinfo->uuid,
|
|
|
0b7161 |
&guidstr);
|
|
|
0b7161 |
|
|
|
0b7161 |
return toks_dprintf(STDOUT_FILENO,
|
|
|
0b7161 |
"toks_uuid:%s\n"
|
|
|
0b7161 |
"toks_syspid:%d\n"
|
|
|
0b7161 |
"toks_systid:%d\n"
|
|
|
0b7161 |
"toks_ctrlpid:%d\n"
|
|
|
0b7161 |
"toks_csyspid:%d\n"
|
|
|
0b7161 |
"toks_allocated:%d\n"
|
|
|
0b7161 |
"toks_available:%d\n"
|
|
|
91a57a |
"toks_pending:%d\n"
|
|
|
bf3927 |
"toks_tused:%d\n"
|
|
|
bf3927 |
"toks_tfree:%d\n"
|
|
|
0b7161 |
"toks_loglevel:%d\n",
|
|
|
0b7161 |
guidstr,
|
|
|
0b7161 |
svcinfo->syspid,
|
|
|
0b7161 |
svcinfo->systid,
|
|
|
0b7161 |
svcinfo->ctrlpid,
|
|
|
0b7161 |
svcinfo->csyspid,
|
|
|
0b7161 |
svcinfo->allocated,
|
|
|
0b7161 |
svcinfo->available,
|
|
|
91a57a |
svcinfo->pending,
|
|
|
bf3927 |
svcinfo->tused,
|
|
|
bf3927 |
svcinfo->tfree,
|
|
|
0b7161 |
svcinfo->loglevel);
|
|
|
0b7161 |
}
|
|
|
0b7161 |
|
|
|
eb3ecd |
static void toks_output_token_info(const struct toks_token_ctx * tokctx)
|
|
|
eb3ecd |
{
|
|
|
eb3ecd |
int idx;
|
|
|
eb3ecd |
const struct toks_token_info * tinfo;
|
|
|
eb3ecd |
char path[2048];
|
|
|
eb3ecd |
|
|
|
533a8c |
toks_dprintf(STDOUT_FILENO,"toks_tokens:{%s",
|
|
|
533a8c |
tokctx->tused ? "\n" : "");
|
|
|
eb3ecd |
|
|
|
eb3ecd |
for (idx=0,tinfo=tokctx->tokens; idx<tokctx->tused; tinfo++) {
|
|
|
eb3ecd |
toks_log_get_arbitrary_process_name(
|
|
|
eb3ecd |
&(nt_cid){.process_id=tinfo->tsyspid,.thread_id=0},
|
|
|
eb3ecd |
path,sizeof(path));
|
|
|
eb3ecd |
|
|
|
eb3ecd |
toks_dprintf(STDOUT_FILENO,
|
|
|
eb3ecd |
"\t{"
|
|
|
eb3ecd |
".token_no=%d, "
|
|
|
eb3ecd |
".token_id=%08X-%08X-%08X-%08X-%08X-%08X, "
|
|
|
eb3ecd |
".token_pid=%d, "
|
|
|
eb3ecd |
".token_syspid=%d, "
|
|
|
eb3ecd |
".token_refstr=``%s''}\n"
|
|
|
eb3ecd |
"\t\t"
|
|
|
eb3ecd |
".client_image=%s\n",
|
|
|
eb3ecd |
++idx,
|
|
|
eb3ecd |
tinfo->keys[0],
|
|
|
eb3ecd |
tinfo->keys[1],
|
|
|
eb3ecd |
tinfo->keys[2],
|
|
|
eb3ecd |
tinfo->keys[3],
|
|
|
eb3ecd |
tinfo->keys[4],
|
|
|
eb3ecd |
tinfo->keys[5],
|
|
|
eb3ecd |
tinfo->tokpid,
|
|
|
eb3ecd |
tinfo->tsyspid,
|
|
|
eb3ecd |
tinfo->meta,
|
|
|
eb3ecd |
path);
|
|
|
eb3ecd |
}
|
|
|
eb3ecd |
|
|
|
eb3ecd |
toks_dprintf(STDOUT_FILENO,"}\n");
|
|
|
533a8c |
|
|
|
533a8c |
toks_dprintf(STDOUT_FILENO,"toks_waiters:{%s",
|
|
|
533a8c |
tokctx->pending ? "\n" : "");
|
|
|
533a8c |
|
|
|
533a8c |
for (idx=0; idx<tokctx->pending; tinfo++) {
|
|
|
533a8c |
toks_log_get_arbitrary_process_name(
|
|
|
533a8c |
&(nt_cid){.process_id=tinfo->tsyspid,.thread_id=0},
|
|
|
533a8c |
path,sizeof(path));
|
|
|
533a8c |
|
|
|
533a8c |
toks_dprintf(STDOUT_FILENO,
|
|
|
533a8c |
"\t{"
|
|
|
533a8c |
".waiter_no=%d, "
|
|
|
533a8c |
".token_id=%08X-%08X-%08X-%08X-%08X-%08X, "
|
|
|
533a8c |
".token_pid=%d, "
|
|
|
533a8c |
".token_syspid=%d, "
|
|
|
533a8c |
".token_refstr=``%s''}\n"
|
|
|
533a8c |
"\t\t"
|
|
|
533a8c |
".client_image=%s\n",
|
|
|
533a8c |
++idx,
|
|
|
533a8c |
tinfo->keys[0],
|
|
|
533a8c |
tinfo->keys[1],
|
|
|
533a8c |
tinfo->keys[2],
|
|
|
533a8c |
tinfo->keys[3],
|
|
|
533a8c |
tinfo->keys[4],
|
|
|
533a8c |
tinfo->keys[5],
|
|
|
533a8c |
tinfo->tokpid,
|
|
|
533a8c |
tinfo->tsyspid,
|
|
|
533a8c |
tinfo->meta,
|
|
|
533a8c |
path);
|
|
|
533a8c |
}
|
|
|
533a8c |
|
|
|
533a8c |
toks_dprintf(STDOUT_FILENO,"}\n");
|
|
|
eb3ecd |
}
|
|
|
eb3ecd |
|
|
|
8b5736 |
static int toks_exit(struct toks_driver_ctx * dctx, int nerrors)
|
|
|
8b5736 |
{
|
|
|
8b5736 |
toks_free_driver_ctx(dctx);
|
|
|
8b5736 |
return nerrors ? 2 : 0;
|
|
|
8b5736 |
}
|
|
|
8b5736 |
|
|
|
8b5736 |
int toks_main(char ** argv, char ** envp)
|
|
|
8b5736 |
{
|
|
|
8b5736 |
int ret;
|
|
|
b27e56 |
int32_t status;
|
|
|
8b5736 |
struct toks_driver_ctx * dctx;
|
|
|
2dcff1 |
struct toks_token_string toks;
|
|
|
0b7161 |
struct toks_service_info svcinfo;
|
|
|
eb3ecd |
struct toks_server_snapshot * snapshot;
|
|
|
8b5736 |
|
|
|
8b5736 |
if ((ret = toks_init()))
|
|
|
8b5736 |
return ret;
|
|
|
8b5736 |
|
|
|
8b5736 |
if ((ret = toks_get_driver_ctx(argv,envp,TOKS_DRIVER_FLAGS,&dctx)))
|
|
|
8b5736 |
return (ret == TOKS_USAGE)
|
|
|
8b5736 |
? !argv || !argv[0] || !argv[1]
|
|
|
8b5736 |
: 2;
|
|
|
8b5736 |
|
|
|
8b5736 |
if (dctx->cctx->drvflags & TOKS_DRIVER_VERSION)
|
|
|
8b5736 |
if ((toks_version(dctx)) < 0)
|
|
|
8b5736 |
return toks_exit(dctx,2);
|
|
|
8b5736 |
|
|
|
2dcff1 |
if (dctx->cctx->drvflags & TOKS_DRIVER_ACTION_ACQUIRE) {
|
|
|
b27e56 |
ret = (status = toks_client_acquire(dctx))
|
|
|
02451d |
? 2 : 0;
|
|
|
02451d |
|
|
|
b27e56 |
switch (status) {
|
|
|
b27e56 |
case NT_STATUS_SUCCESS:
|
|
|
b27e56 |
break;
|
|
|
b27e56 |
|
|
|
b27e56 |
case NT_STATUS_TIMEOUT:
|
|
|
b27e56 |
toks_dprintf(STDERR_FILENO,
|
|
|
b27e56 |
"%s: the operataion timed out [0x%x].\n",
|
|
|
b27e56 |
toks_log_basename(argv[0]),status);
|
|
|
b27e56 |
break;
|
|
|
b27e56 |
|
|
|
b27e56 |
default:
|
|
|
b27e56 |
toks_dprintf(STDERR_FILENO,
|
|
|
b27e56 |
"%s: the operataion has failed [0x%x].\n",
|
|
|
b27e56 |
toks_log_basename(argv[0]),status);
|
|
|
b27e56 |
}
|
|
|
b27e56 |
|
|
|
2dcff1 |
if (ret == 0) {
|
|
|
2dcff1 |
toks_client_token_to_str(dctx,&toks);
|
|
|
2dcff1 |
toks_dprintf(STDOUT_FILENO,"%s\n",toks.token);
|
|
|
2dcff1 |
}
|
|
|
2dcff1 |
}
|
|
|
2dcff1 |
|
|
|
867b30 |
if (dctx->cctx->drvflags & TOKS_DRIVER_ACTION_RELEASE) {
|
|
|
867b30 |
ret = toks_client_release(dctx)
|
|
|
867b30 |
? 2 : 0;
|
|
|
867b30 |
|
|
|
867b30 |
if (ret == 0) {
|
|
|
867b30 |
toks_client_token_to_str(dctx,&toks);
|
|
|
867b30 |
toks_dprintf(STDOUT_FILENO,"token %s has been released\n",toks.token);
|
|
|
867b30 |
}
|
|
|
867b30 |
|
|
|
867b30 |
if (ret == 2) {
|
|
|
867b30 |
toks_dprintf(STDERR_FILENO,"error: invalid token");
|
|
|
867b30 |
}
|
|
|
867b30 |
}
|
|
|
867b30 |
|
|
|
bd4f0c |
if (dctx->cctx->drvflags & TOKS_DRIVER_ACTION_NTOKENS_GET) {
|
|
|
bd4f0c |
toks_dprintf(STDOUT_FILENO,
|
|
|
bd4f0c |
"toks_ntokens:%d\n",
|
|
|
bd4f0c |
toks_get_driver_ntokens(dctx));
|
|
|
bd4f0c |
}
|
|
|
bd4f0c |
|
|
|
0f44d8 |
if (dctx->cctx->drvflags & TOKS_DRIVER_ACTION_NTOKENS_SET) {
|
|
|
0f44d8 |
status = toks_service_ioctl(
|
|
|
0f44d8 |
dctx,TOKS_IOCTL_SET_TOKEN_COUNT,
|
|
|
0f44d8 |
&(uintptr_t){toks_get_driver_ntokens(dctx)},
|
|
|
0f44d8 |
0);
|
|
|
0f44d8 |
|
|
|
0f44d8 |
ret = status ? 2 : 0;
|
|
|
0f44d8 |
|
|
|
0f44d8 |
switch (status) {
|
|
|
0f44d8 |
case NT_STATUS_SUCCESS:
|
|
|
0f44d8 |
toks_dprintf(STDERR_FILENO,
|
|
|
0f44d8 |
"%s: the service's ntokens parameter "
|
|
|
0f44d8 |
"was successfully set to %d\n",
|
|
|
0f44d8 |
toks_log_basename(argv[0]),
|
|
|
0f44d8 |
toks_get_driver_ntokens(dctx));
|
|
|
0f44d8 |
break;
|
|
|
0f44d8 |
|
|
|
0f44d8 |
default:
|
|
|
0f44d8 |
toks_dprintf(STDERR_FILENO,
|
|
|
0f44d8 |
"%s: the TOKS_IOCTL_SET_TOKEN_COUNT "
|
|
|
0f44d8 |
"ioctl operataion has failed "
|
|
|
0f44d8 |
"(check the system's documentation) [0x%x].",
|
|
|
0f44d8 |
toks_log_basename(argv[0]),status);
|
|
|
0f44d8 |
}
|
|
|
0f44d8 |
}
|
|
|
0f44d8 |
|
|
|
7f4116 |
if (dctx->cctx->drvflags & TOKS_DRIVER_ACTION_LOGLEVEL_GET) {
|
|
|
7f4116 |
toks_dprintf(STDOUT_FILENO,
|
|
|
7f4116 |
"toks_loglevel:%d\n",
|
|
|
7f4116 |
dctx->cctx->loglevel);
|
|
|
7f4116 |
}
|
|
|
7f4116 |
|
|
|
7f4116 |
if (dctx->cctx->drvflags & TOKS_DRIVER_ACTION_LOGLEVEL_SET) {
|
|
|
7f4116 |
status = toks_service_ioctl(
|
|
|
7f4116 |
dctx,TOKS_IOCTL_SET_LOG_LEVEL,
|
|
|
7f4116 |
&(uintptr_t){dctx->cctx->loglevel},
|
|
|
7f4116 |
0);
|
|
|
7f4116 |
|
|
|
7f4116 |
ret = status ? 2 : 0;
|
|
|
7f4116 |
|
|
|
7f4116 |
switch (status) {
|
|
|
7f4116 |
case NT_STATUS_SUCCESS:
|
|
|
7f4116 |
toks_dprintf(STDERR_FILENO,
|
|
|
7f4116 |
"%s: the service's log-level parameter "
|
|
|
7f4116 |
"was successfully set to %d\n",
|
|
|
7f4116 |
toks_log_basename(argv[0]),
|
|
|
7f4116 |
dctx->cctx->loglevel);
|
|
|
7f4116 |
break;
|
|
|
7f4116 |
|
|
|
7f4116 |
default:
|
|
|
7f4116 |
toks_dprintf(STDERR_FILENO,
|
|
|
7f4116 |
"%s: the TOKS_IOCTL_SET_LOG_LEVEL "
|
|
|
7f4116 |
"ioctl operataion has failed "
|
|
|
7f4116 |
"(check the system's documentation) [0x%x].",
|
|
|
7f4116 |
toks_log_basename(argv[0]),status);
|
|
|
7f4116 |
}
|
|
|
7f4116 |
}
|
|
|
7f4116 |
|
|
|
0b7161 |
if (dctx->cctx->drvflags & TOKS_DRIVER_ACTION_SVCINFO_GET) {
|
|
|
0b7161 |
status = toks_client_query_service(dctx,&svcinfo);
|
|
|
0b7161 |
ret = status ? 2 : 0;
|
|
|
0b7161 |
|
|
|
0b7161 |
switch (status) {
|
|
|
0b7161 |
case NT_STATUS_SUCCESS:
|
|
|
0b7161 |
toks_output_service_info(&svcinfo);
|
|
|
0b7161 |
break;
|
|
|
0b7161 |
|
|
|
0b7161 |
default:
|
|
|
0b7161 |
toks_dprintf(STDERR_FILENO,
|
|
|
0b7161 |
"%s: the TOKS_IOCTL_GET_SERVICE_INFO "
|
|
|
0b7161 |
"ioctl operataion has failed "
|
|
|
0b7161 |
"(check the system's documentation) [0x%x].",
|
|
|
0b7161 |
toks_log_basename(argv[0]),status);
|
|
|
0b7161 |
}
|
|
|
0b7161 |
}
|
|
|
0b7161 |
|
|
|
0b7161 |
if (dctx->cctx->drvflags & TOKS_DRIVER_ACTION_SVCINFO_LOG) {
|
|
|
0b7161 |
status = toks_service_ioctl(dctx,TOKS_IOCTL_LOG_SERVICE_INFO,0,0);
|
|
|
0b7161 |
ret = status ? 2 : 0;
|
|
|
0b7161 |
|
|
|
0b7161 |
switch (status) {
|
|
|
0b7161 |
case NT_STATUS_SUCCESS:
|
|
|
0b7161 |
toks_dprintf(STDERR_FILENO,
|
|
|
0b7161 |
"%s: a service info log record "
|
|
|
0b7161 |
"was successfully created\n",
|
|
|
0b7161 |
toks_log_basename(argv[0]));
|
|
|
0b7161 |
break;
|
|
|
0b7161 |
|
|
|
0b7161 |
default:
|
|
|
0b7161 |
toks_dprintf(STDERR_FILENO,
|
|
|
0b7161 |
"%s: the TOKS_IOCTL_LOG_SERVICE_INFO "
|
|
|
0b7161 |
"ioctl operataion has failed "
|
|
|
0b7161 |
"(check the system's documentation) [0x%x].",
|
|
|
0b7161 |
toks_log_basename(argv[0]),status);
|
|
|
0b7161 |
}
|
|
|
0b7161 |
}
|
|
|
0b7161 |
|
|
|
eb3ecd |
if (dctx->cctx->drvflags & TOKS_DRIVER_ACTION_TOKINFO_GET) {
|
|
|
eb3ecd |
status = toks_get_server_snapshot(dctx,&snapshot);
|
|
|
eb3ecd |
ret = status ? 2 : 0;
|
|
|
eb3ecd |
|
|
|
eb3ecd |
switch (status) {
|
|
|
eb3ecd |
case NT_STATUS_SUCCESS:
|
|
|
eb3ecd |
toks_output_service_info(&snapshot->svcinfo);
|
|
|
eb3ecd |
toks_output_token_info(snapshot->tokctx);
|
|
|
eb3ecd |
toks_free_server_snapshot(snapshot);
|
|
|
eb3ecd |
break;
|
|
|
eb3ecd |
|
|
|
eb3ecd |
default:
|
|
|
eb3ecd |
toks_dprintf(STDERR_FILENO,
|
|
|
eb3ecd |
"%s: the TOKS_IOCTL_GET_TOKEN_INFO "
|
|
|
eb3ecd |
"ioctl operataion has failed "
|
|
|
eb3ecd |
"(check the system's documentation) [0x%x].",
|
|
|
eb3ecd |
toks_log_basename(argv[0]),status);
|
|
|
eb3ecd |
}
|
|
|
eb3ecd |
}
|
|
|
eb3ecd |
|
|
|
5e0b43 |
if (dctx->cctx->drvflags & TOKS_DRIVER_ACTION_TOKINFO_LOG) {
|
|
|
5e0b43 |
status = toks_service_ioctl(dctx,TOKS_IOCTL_LOG_TOKEN_INFO,0,0);
|
|
|
5e0b43 |
ret = status ? 2 : 0;
|
|
|
5e0b43 |
|
|
|
5e0b43 |
switch (status) {
|
|
|
5e0b43 |
case NT_STATUS_SUCCESS:
|
|
|
5e0b43 |
toks_dprintf(STDERR_FILENO,
|
|
|
5e0b43 |
"%s: a service info log record, "
|
|
|
5e0b43 |
"followed by a info table for currently "
|
|
|
5e0b43 |
"allocated tokens, was successfully created\n",
|
|
|
5e0b43 |
toks_log_basename(argv[0]));
|
|
|
5e0b43 |
break;
|
|
|
5e0b43 |
|
|
|
5e0b43 |
default:
|
|
|
5e0b43 |
toks_dprintf(STDERR_FILENO,
|
|
|
5e0b43 |
"%s: the TOKS_IOCTL_LOG_TOKEN_INFO "
|
|
|
5e0b43 |
"ioctl operataion has failed "
|
|
|
5e0b43 |
"(check the system's documentation) [0x%x].",
|
|
|
5e0b43 |
toks_log_basename(argv[0]),status);
|
|
|
5e0b43 |
}
|
|
|
5e0b43 |
}
|
|
|
5e0b43 |
|
|
|
255212 |
if (dctx->cctx->drvflags & TOKS_DRIVER_ACTION_ABORT) {
|
|
|
255212 |
ret = (status = toks_service_abort(dctx))
|
|
|
255212 |
? 2 : 0;
|
|
|
255212 |
|
|
|
255212 |
switch (status) {
|
|
|
255212 |
case NT_STATUS_SUCCESS:
|
|
|
255212 |
toks_dprintf(STDERR_FILENO,
|
|
|
255212 |
"%s: the server responded with no error.\n",
|
|
|
255212 |
toks_log_basename(argv[0]),status);
|
|
|
255212 |
break;
|
|
|
255212 |
|
|
|
255212 |
case NT_STATUS_ACCESS_DENIED:
|
|
|
255212 |
toks_dprintf(STDERR_FILENO,
|
|
|
255212 |
"%s: the abort operataion timed (access denied) [0x%x].\n",
|
|
|
255212 |
toks_log_basename(argv[0]),status);
|
|
|
255212 |
break;
|
|
|
255212 |
|
|
|
255212 |
default:
|
|
|
255212 |
toks_dprintf(STDERR_FILENO,
|
|
|
255212 |
"%s: the abort operataion failed ",
|
|
|
255212 |
"(check the system's documentation) [0x%x].",
|
|
|
255212 |
toks_log_basename(argv[0]),status);
|
|
|
255212 |
}
|
|
|
255212 |
}
|
|
|
255212 |
|
|
|
618937 |
return (dctx->cctx->drvflags & TOKS_DRIVER_MODE_SERVER)
|
|
|
618937 |
? NT_STATUS_SERVICE_NOTIFICATION
|
|
|
618937 |
: toks_exit(dctx,ret);
|
|
|
8b5736 |
}
|