| |
| |
| |
| |
| |
| |
| #include <ntapi/ntapi.h> |
| #include <ntapi/nt_atomic.h> |
| |
| #include <stdint.h> |
| |
| #include <toksvc/toksvc.h> |
| #include "toksvc_init_impl.h" |
| #include "toksvc_nolibc_impl.h" |
| |
| #define ARGV_DRIVER |
| |
| #include "toksvc_version.h" |
| #include "toksvc_daemon_impl.h" |
| #include "toksvc_dprintf_impl.h" |
| #include "toksvc_driver_impl.h" |
| #include "argv/argv.h" |
| |
| |
| #include <psxtypes/section/freestd.h> |
| |
| __attr_section_decl__(".freestd") |
| static const nt_tty_affiliation tty_affiliation |
| __attr_section__(".freestd") |
| = NT_TTY_AFFILIATION_DEFAULT; |
| |
| |
| const ntapi_vtbl * toks_ntapi; |
| |
| |
| static struct toks_daemon_ctx toks_daemon_ctx; |
| static const nt_guid toks_daemon_default_guid = TOKS_PORT_GUID_DAEMON; |
| static const wchar16_t toks_service_name[6] = TOKS_PORT_NAME_PREFIX; |
| |
| |
| static const struct toks_source_version toks_src_version = { |
| TOKS_TAG_VER_MAJOR, |
| TOKS_TAG_VER_MINOR, |
| TOKS_TAG_VER_PATCH, |
| TOKSVC_GIT_VERSION |
| }; |
| |
| struct toks_driver_ctx_alloc { |
| struct argv_meta * meta; |
| struct toks_driver_ctx_impl ctx; |
| uint64_t guard; |
| }; |
| |
| struct toks_split_vector { |
| char ** targv; |
| char ** eargv; |
| }; |
| |
| static uint32_t toks_argv_flags(uint32_t flags) |
| { |
| uint32_t ret = ARGV_CLONE_VECTOR; |
| |
| if (flags & TOKS_DRIVER_VERBOSITY_NONE) |
| ret |= ARGV_VERBOSITY_NONE; |
| |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| ret |= ARGV_VERBOSITY_ERRORS; |
| |
| if (flags & TOKS_DRIVER_VERBOSITY_STATUS) |
| ret |= ARGV_VERBOSITY_STATUS; |
| |
| return ret; |
| } |
| |
| static int toks_driver_usage( |
| const char * program, |
| const char * arg, |
| const struct argv_option ** optv, |
| struct argv_meta * meta) |
| { |
| char header[512]; |
| |
| snprintf(header,sizeof(header), |
| "Usage: %s [options] <file>...\n" "Options:\n", |
| program); |
| |
| argv_usage(STDOUT_FILENO,header,optv,arg); |
| argv_free(meta); |
| |
| return TOKS_USAGE; |
| } |
| |
| static int64_t toks_arg_to_int64(struct argv_entry * entry) |
| { |
| int64_t ret; |
| const char * ch; |
| |
| for (ret=0, ch=entry->arg; *ch && (ret>=0); ch++) { |
| if ((*ch < '0') || (*ch >'9')) |
| return (-1); |
| |
| ret *= 10; |
| ret += (*ch - '0'); |
| } |
| |
| return ret; |
| } |
| |
| static int32_t toks_arg_to_int32(struct argv_entry * entry) |
| { |
| int64_t ret = toks_arg_to_int64(entry); |
| return (ret >= 0) && (ret <= 0x7fffffff) |
| ? ret : (-1); |
| } |
| |
| static int32_t toks_query_performance_counters_failover(nt_filetime * ticks) |
| { |
| (void)ticks; |
| return 0; |
| } |
| |
| static int32_t toks_daemon_library_once; |
| |
| static int32_t toks_daemon_library_init(void) |
| { |
| int32_t status; |
| int argc; |
| char ** argv; |
| char ** envp; |
| nt_rtdata * rtdata; |
| nt_timeout timeout; |
| |
| switch (at_locked_cas_32(&toks_daemon_library_once,0,1)) { |
| case 0: |
| status = ntapi->tt_get_argv_envp_utf8( |
| &argc,&argv,&envp, |
| 0,0,0); |
| |
| if (status) { |
| at_store_32(&toks_daemon_library_once,3); |
| return status; |
| } |
| |
| if ((status = ntapi->tt_get_runtime_data(&rtdata,0))) { |
| at_store_32(&toks_daemon_library_once,3); |
| return status; |
| } |
| |
| if (!rtdata->argv) { |
| rtdata->argc = argc; |
| rtdata->argv = argv; |
| rtdata->envp = envp; |
| } |
| |
| ntapi->tt_guid_copy( |
| &rtdata->srv_guid, |
| &toks_daemon_default_guid); |
| |
| at_locked_inc_32(&toks_daemon_library_once); |
| return 0; |
| |
| case 1: |
| timeout.quad = -10; |
| |
| for (; (at_locked_cas_32(&toks_daemon_library_once,0,1) == 1); ) |
| ntapi->zw_delay_execution( |
| NT_SYNC_ALERTABLE, |
| &timeout); |
| |
| return (toks_daemon_library_once == 2) |
| ? 0 : -1; |
| |
| case 2: |
| return 0; |
| |
| case 3: |
| default: |
| return -1; |
| } |
| |
| return NT_STATUS_INTERNAL_ERROR; |
| } |
| |
| static struct toks_driver_ctx_impl * toks_driver_ctx_alloc( |
| struct argv_meta * meta, |
| const struct toks_common_ctx * cctx) |
| { |
| struct toks_driver_ctx_alloc * ictx; |
| size_t size; |
| nt_runtime_data * rtdata; |
| |
| switch (ntapi->tt_get_runtime_data(&rtdata,0)) { |
| case NT_STATUS_SUCCESS: |
| break; |
| |
| case NT_STATUS_MORE_PROCESSING_REQUIRED: |
| toks_daemon_library_init(); |
| |
| if (ntapi->tt_get_runtime_data(&rtdata,0)) |
| return 0; |
| |
| break; |
| |
| default: |
| return 0; |
| } |
| |
| size = sizeof(struct toks_driver_ctx_alloc); |
| |
| if (!(ictx = calloc(1,size))) |
| return 0; |
| |
| if (cctx) |
| memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx)); |
| |
| ictx->ctx.ticks.qpc = toks_query_performance_counters_failover; |
| ictx->ctx.ticks.pcfreq.quad = 0; |
| |
| ictx->meta = meta; |
| ictx->ctx.rtdata = rtdata; |
| return &ictx->ctx; |
| } |
| |
| static int toks_get_driver_ctx_fail(struct argv_meta * meta) |
| { |
| argv_free(meta); |
| return -1; |
| } |
| |
| #define TOKS_SARGV_ELEMENTS 1024 |
| |
| static int toks_split_argv( |
| char ** argv, |
| struct toks_split_vector * sargv) |
| { |
| ptrdiff_t argc; |
| char ** parg; |
| |
| |
| for (parg=argv; *parg; ) |
| parg++; |
| |
| if ((argc = parg - argv) >= TOKS_SARGV_ELEMENTS) |
| return -1; |
| |
| |
| ntapi->tt_aligned_block_memset( |
| (uintptr_t *)sargv->targv, |
| 0,TOKS_SARGV_ELEMENTS*sizeof(char *)); |
| |
| ntapi->tt_aligned_block_memcpy( |
| (uintptr_t *)sargv->targv, |
| (uintptr_t *)argv, |
| argc*sizeof(char *)); |
| |
| |
| for (parg=sargv->targv; *parg; parg++) { |
| if (!(strcmp(*parg,"-e")) || !(strcmp(*parg,"--exec"))) { |
| sargv->eargv = &argv[parg-sargv->targv]; |
| sargv->eargv++; |
| *parg = 0; |
| return 0; |
| } |
| } |
| |
| return 0; |
| } |
| |
| int toks_get_driver_ctx( |
| char ** argv, |
| char ** envp, |
| uint32_t flags, |
| struct toks_driver_ctx ** pctx) |
| { |
| int32_t status; |
| struct toks_driver_ctx_impl * ctx; |
| struct toks_common_ctx cctx; |
| struct toks_split_vector sargv; |
| const struct argv_option * optv[TOKS_OPTV_ELEMENTS]; |
| struct argv_meta * meta; |
| struct argv_entry * entry; |
| struct argv_entry * uuid; |
| struct argv_entry * pid; |
| struct argv_entry * syspid; |
| struct argv_entry * cfpid; |
| struct argv_entry * cspid; |
| struct argv_entry * msecs; |
| struct toks_token_string key; |
| size_t keylen; |
| uintptr_t opdata; |
| nt_guid svcguid; |
| const char * program; |
| const char * refstr; |
| int ntokens; |
| int atokens; |
| int loglevel; |
| int32_t tokpid; |
| int32_t tsyspid; |
| int32_t ctrlpid; |
| int32_t csyspid; |
| int64_t timeout; |
| void * hlog; |
| void * hkernel32; |
| char * targv[TOKS_SARGV_ELEMENTS]; |
| |
| (void)envp; |
| |
| if (toks_init()) |
| return -1; |
| |
| argv_optv_init(toks_default_options,optv); |
| |
| sargv.targv = targv; |
| sargv.eargv = 0; |
| |
| if (toks_split_argv(argv,&sargv)) |
| return -1; |
| |
| if (!(meta = argv_get( |
| sargv.targv,optv, |
| toks_argv_flags(flags), |
| STDERR_FILENO))) |
| return -1; |
| |
| if (!(flags & TOKS_DRIVER_MODE_CLIENT)) |
| flags |= TOKS_DRIVER_MODE_SERVER; |
| |
| hlog = 0; |
| uuid = 0; |
| tokpid = 0; |
| tsyspid = 0; |
| ctrlpid = 0; |
| csyspid = 0; |
| keylen = 0; |
| refstr = 0; |
| ntokens = 0; |
| loglevel = 0; |
| timeout = (-1); |
| program = argv_program_name(argv[0]); |
| |
| memset(&cctx,0,sizeof(cctx)); |
| cctx.drvflags = flags; |
| cctx.eargv = sargv.eargv; |
| |
| if (!argv[1] && (flags & TOKS_DRIVER_VERBOSITY_USAGE)) |
| return toks_driver_usage(program,0,optv,meta); |
| |
| for (entry=meta->entries; entry->fopt || entry->arg; entry++) { |
| if (entry->fopt) { |
| switch (entry->tag) { |
| case TAG_HELP: |
| if (flags & TOKS_DRIVER_VERBOSITY_USAGE) |
| return toks_driver_usage(program,entry->arg,optv,meta); |
| |
| case TAG_VERSION: |
| cctx.drvflags |= TOKS_DRIVER_VERSION; |
| break; |
| |
| case TAG_DAEMON: |
| if (!strcmp("always",entry->arg)) |
| cctx.drvflags |= TOKS_DRIVER_DAEMON_ALWAYS; |
| |
| else if (!strcmp("never",entry->arg)) |
| cctx.drvflags |= TOKS_DRIVER_DAEMON_NEVER; |
| |
| break; |
| |
| case TAG_SYSROOT: |
| cctx.sysroot = entry->arg; |
| break; |
| |
| case TAG_UUID: |
| uuid = entry; |
| break; |
| |
| case TAG_REFSTR: |
| refstr = entry->arg; |
| break; |
| |
| case TAG_PID: |
| tokpid = toks_arg_to_int32((pid=entry)); |
| break; |
| |
| case TAG_SYSPID: |
| tsyspid = toks_arg_to_int32((syspid=entry)); |
| break; |
| |
| case TAG_CTRLPID: |
| ctrlpid = toks_arg_to_int32((cfpid=entry)); |
| break; |
| |
| case TAG_CSYSPID: |
| csyspid = toks_arg_to_int32((cspid=entry)); |
| break; |
| |
| case TAG_LOGLEVEL: |
| loglevel = toks_arg_to_int32(entry); |
| loglevel = (loglevel > 9) ? (-1) : loglevel; |
| cctx.loglevel = loglevel; |
| break; |
| |
| case TAG_TIMEOUT: |
| timeout = toks_arg_to_int64((msecs=entry)); |
| timeout = (timeout < 0) ? (-2) : timeout; |
| break; |
| |
| case TAG_TOKENS: |
| ntokens = toks_arg_to_int32(entry); |
| ntokens = (ntokens > 9999) ? (-1) : ntokens; |
| break; |
| |
| case TAG_CONNECT: |
| cctx.drvflags &= ~(uint64_t)TOKS_DRIVER_MODE_SERVER; |
| cctx.drvflags |= TOKS_DRIVER_MODE_CLIENT; |
| break; |
| |
| case TAG_ABORT: |
| cctx.drvflags &= ~(uint64_t)TOKS_DRIVER_MODE_SERVER; |
| cctx.drvflags |= TOKS_DRIVER_MODE_CLIENT; |
| cctx.drvflags |= TOKS_DRIVER_ACTION_ABORT; |
| break; |
| |
| case TAG_ACQUIRE: |
| cctx.drvflags &= ~(uint64_t)TOKS_DRIVER_MODE_SERVER; |
| cctx.drvflags |= TOKS_DRIVER_MODE_CLIENT; |
| cctx.drvflags |= TOKS_DRIVER_ACTION_ACQUIRE; |
| break; |
| |
| case TAG_RELEASE: |
| cctx.drvflags &= ~(uint64_t)TOKS_DRIVER_MODE_SERVER; |
| cctx.drvflags |= TOKS_DRIVER_MODE_CLIENT; |
| cctx.drvflags |= TOKS_DRIVER_ACTION_RELEASE; |
| |
| keylen = toks_strlen(entry->arg); |
| |
| ntapi->tt_generic_memset( |
| &key,0,sizeof(key)); |
| |
| if (keylen < sizeof(key.token)) |
| ntapi->tt_generic_memcpy( |
| &key.token,entry->arg, |
| keylen); |
| break; |
| |
| case TAG_LOGFILE: |
| cctx.logfile = entry->arg; |
| break; |
| |
| case TAG_NTOKENSGET: |
| cctx.drvflags &= ~(uint64_t)TOKS_DRIVER_MODE_SERVER; |
| cctx.drvflags |= TOKS_DRIVER_MODE_CLIENT; |
| cctx.drvflags |= TOKS_DRIVER_ACTION_NTOKENS_GET; |
| break; |
| |
| case TAG_NTOKENSSET: |
| cctx.drvflags &= ~(uint64_t)TOKS_DRIVER_MODE_SERVER; |
| cctx.drvflags |= TOKS_DRIVER_MODE_CLIENT; |
| cctx.drvflags |= TOKS_DRIVER_ACTION_NTOKENS_SET; |
| ntokens = toks_arg_to_int32(entry); |
| break; |
| } |
| } else |
| |
| return toks_driver_usage(program,0,optv,meta); |
| } |
| |
| if ((cctx.drvflags & TOKS_DRIVER_MODE_CLIENT) && (tokpid < 0)) { |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: %s is not a valid framework process id.", |
| program,pid->arg); |
| return toks_get_driver_ctx_fail(meta); |
| } |
| |
| if ((cctx.drvflags & TOKS_DRIVER_MODE_CLIENT) && (tsyspid < 0)) { |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: %s is not a valid system process id.", |
| program,syspid->arg); |
| return toks_get_driver_ctx_fail(meta); |
| } |
| |
| if ((cctx.drvflags & TOKS_DRIVER_MODE_SERVER) && (ctrlpid < 0)) { |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: %s is not a valid controlling " |
| "framework process id.", |
| program,cfpid->arg); |
| return toks_get_driver_ctx_fail(meta); |
| } |
| |
| if ((cctx.drvflags & TOKS_DRIVER_MODE_SERVER) && (csyspid < 0)) { |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: %s is not a valid controlling " |
| "system process id.", |
| program,cspid->arg); |
| return toks_get_driver_ctx_fail(meta); |
| } |
| |
| if ((cctx.drvflags & TOKS_DRIVER_MODE_CLIENT) && (timeout < (-1))) { |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: %s is not a valid timeout in milliseconds.", |
| program,msecs->arg); |
| return toks_get_driver_ctx_fail(meta); |
| } |
| |
| if ((ntokens == 0) && !(cctx.drvflags & TOKS_DRIVER_VERSION)) { |
| ntokens = (-1); |
| } |
| |
| if (ntokens == 0) { |
| cctx.drvflags &= ~(uint64_t)TOKS_DRIVER_MODE_SERVER; |
| } |
| |
| if ((cctx.drvflags & TOKS_DRIVER_MODE_SERVER) && (ntokens < 0)) { |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: number of tokens not set or is invalid.", |
| program); |
| return toks_get_driver_ctx_fail(meta); |
| } |
| |
| if ((cctx.drvflags & TOKS_DRIVER_MODE_SERVER) && (loglevel < 0)) { |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: loglevel must be in the range of 0..9.", |
| program); |
| return toks_get_driver_ctx_fail(meta); |
| } |
| |
| if (uuid && ntapi->tt_string_to_guid_utf8(uuid->arg,&svcguid)) { |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: '%s' is not a valid service guid (did you forget the braces?)", |
| program,uuid->arg); |
| return toks_get_driver_ctx_fail(meta); |
| |
| } |
| |
| if (cctx.sysroot && toks_open_dir(&cctx.hroot,0,cctx.sysroot,false)) { |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: could not open sysroot directory '%s'", |
| program,cctx.sysroot); |
| return toks_get_driver_ctx_fail(meta); |
| } |
| |
| if (!(ctx = toks_driver_ctx_alloc(meta,&cctx))) |
| return toks_get_driver_ctx_fail(meta); |
| |
| if (ctx->rtdata->hroot && cctx.hroot) { |
| ntapi->zw_close(ctx->rtdata->hroot); |
| ctx->rtdata->hroot = cctx.hroot; |
| } |
| |
| if (cctx.logfile && toks_open_log_file(&hlog,ctx->rtdata->hroot,cctx.logfile,false)) { |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: could not create logfile '%s'", |
| program,cctx.logfile); |
| return toks_get_driver_ctx_fail(meta); |
| } |
| |
| if (ctx->rtdata->hlog && cctx.logfile) { |
| ntapi->zw_close(ctx->rtdata->hlog); |
| ctx->rtdata->hlog = hlog; |
| } |
| |
| if ((cctx.drvflags & TOKS_DRIVER_ACTION_RELEASE)) { |
| if (toks_client_str_to_token(&ctx->ctx,&key)) { |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: [%s] is not a valid token.", |
| program,key.token); |
| return toks_get_driver_ctx_fail(meta); |
| } |
| } |
| |
| ntapi->tt_guid_copy( |
| &ctx->uuid, |
| uuid ? &svcguid : &ctx->rtdata->srv_guid); |
| |
| if ((toks_ntapi->tt_create_private_event( |
| &ctx->hevent, |
| NT_NOTIFICATION_EVENT, |
| NT_EVENT_NOT_SIGNALED))) |
| return toks_get_driver_ctx_fail(meta); |
| |
| if ((ntapi->tt_open_dev_object_directory( |
| &ctx->hsvcdir, |
| NT_SEC_READ_CONTROL |
| | NT_DIRECTORY_QUERY |
| | NT_DIRECTORY_TRAVERSE |
| | NT_DIRECTORY_CREATE_OBJECT |
| | NT_DIRECTORY_CREATE_SUBDIRECTORY, |
| toks_service_name, |
| &toks_daemon_default_guid))) |
| return toks_get_driver_ctx_fail(meta); |
| |
| if ((hkernel32 = pe_get_kernel32_module_handle())) |
| if ((ctx->ticks.qpc = pe_get_procedure_address( |
| hkernel32,"QueryPerformanceCounter"))) |
| ntapi->zw_query_performance_counter( |
| &(nt_filetime){{0,0}}, |
| &ctx->ticks.pcfreq); |
| |
| |
| atokens = ntokens; |
| atokens += 0x1fff; |
| atokens |= 0xfff; |
| atokens ^= 0xfff; |
| |
| ctx->hlog = hlog; |
| ctx->tokpid = tokpid; |
| ctx->tsyspid = tsyspid; |
| ctx->ctrlpid = ctrlpid; |
| ctx->csyspid = csyspid; |
| ctx->ntokens = ntokens; |
| ctx->atokens = atokens; |
| ctx->timeout = timeout; |
| ctx->ctx.program = program; |
| ctx->ctx.cctx = &ctx->cctx; |
| ctx->cctx.uuid = &ctx->uuid; |
| |
| ctx->rtdata->hroot = cctx.hroot; |
| ctx->rtdata->hlog = hlog ? hlog : ctx->rtdata->hlog; |
| |
| toks_set_driver_refstr(&ctx->ctx,refstr); |
| |
| if (cctx.drvflags & TOKS_DRIVER_MODE_SERVER) { |
| if (!(ctx->waiters = toks_calloc( |
| TOKS_MAX_WAITERS, |
| sizeof(struct toks_waiter)))) |
| return toks_get_driver_ctx_fail(meta); |
| |
| toks_daemon_ctx.driver_ctx = &ctx->ctx; |
| toks_daemon_ctx.waiter_base = ctx->waiters; |
| toks_daemon_ctx.waiter_first = ctx->waiters; |
| toks_daemon_ctx.waiter_next = ctx->waiters; |
| toks_daemon_ctx.waiter_cap = &ctx->waiters[TOKS_MAX_WAITERS]; |
| |
| |
| if (!(ctx->tokens = toks_calloc(atokens,sizeof(*ctx->tokens)))) |
| return toks_get_driver_ctx_fail(meta); |
| |
| if (toks_daemon_init(&toks_daemon_ctx,&ctx->uuid)) |
| return toks_get_driver_ctx_fail(meta); |
| } |
| |
| if (cctx.drvflags & TOKS_DRIVER_MODE_CLIENT) { |
| if (cctx.drvflags & TOKS_DRIVER_DAEMON_ALWAYS) { |
| toks_daemon_ctx.driver_ctx = &ctx->ctx; |
| |
| switch ((status = toks_daemon_init(&toks_daemon_ctx,0))) { |
| case NT_STATUS_SUCCESS: |
| break; |
| |
| default: |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: failed to initialize signal handling " |
| "(check the system's documentation) [0x%x].", |
| program,status); |
| |
| return toks_get_driver_ctx_fail(meta); |
| } |
| } |
| |
| switch ((status = toks_client_connect(&ctx->ctx))) { |
| case NT_STATUS_SUCCESS: |
| break; |
| |
| case NT_STATUS_OBJECT_NAME_NOT_FOUND: |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: could not connect " |
| "(server not running) [0x%x].", |
| program,status); |
| |
| return toks_get_driver_ctx_fail(meta); |
| |
| case NT_STATUS_CONNECTION_REFUSED: |
| case NT_STATUS_PORT_CONNECTION_REFUSED: |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: could not connect " |
| "(connection refused) [0x%x].", |
| program,status); |
| |
| return toks_get_driver_ctx_fail(meta); |
| |
| case NT_STATUS_ACCESS_DENIED: |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: could not connect " |
| "(access denied) [0x%x].", |
| program,status); |
| |
| return toks_get_driver_ctx_fail(meta); |
| |
| default: |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: could not connect " |
| "(check the system's documentation) [0x%x].", |
| program,status); |
| |
| return toks_get_driver_ctx_fail(meta); |
| } |
| |
| if (cctx.drvflags & TOKS_DRIVER_ACTION_NTOKENS_GET) { |
| status = toks_service_ioctl( |
| &ctx->ctx,TOKS_IOCTL_GET_TOKEN_COUNT, |
| &opdata,0); |
| |
| switch (status) { |
| case NT_STATUS_SUCCESS: |
| ctx->ntokens = opdata; |
| break; |
| |
| default: |
| if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) |
| toks_dprintf(STDERR_FILENO, |
| "%s: error: could not obtain the current " |
| "overall number of tokens " |
| "(check the system's documentation) [0x%x].", |
| program,status); |
| |
| return toks_get_driver_ctx_fail(meta); |
| } |
| } |
| } |
| |
| *pctx = &ctx->ctx; |
| return TOKS_OK; |
| } |
| |
| static void toks_free_driver_ctx_impl(struct toks_driver_ctx_alloc * ictx) |
| { |
| if (ictx->ctx.hevent) |
| ntapi->zw_close(ictx->ctx.hevent); |
| |
| if (ictx->ctx.hsvcdir) |
| ntapi->zw_close(ictx->ctx.hsvcdir); |
| |
| if (ictx->ctx.hsvclink) |
| ntapi->zw_close(ictx->ctx.hsvclink); |
| |
| if (ictx->ctx.hservice) |
| ntapi->zw_close(ictx->ctx.hservice); |
| |
| if (ictx->ctx.hserver) |
| ntapi->zw_close(ictx->ctx.hserver); |
| |
| if (ictx->ctx.hlog) |
| ntapi->zw_close(ictx->ctx.hlog); |
| |
| if (ictx->ctx.tokens) |
| toks_free(ictx->ctx.tokens); |
| |
| if (ictx->ctx.waiters) |
| toks_free(ictx->ctx.waiters); |
| |
| argv_free(ictx->meta); |
| free(ictx); |
| } |
| |
| void toks_free_driver_ctx(struct toks_driver_ctx * ctx) |
| { |
| struct toks_driver_ctx_alloc * ictx; |
| uintptr_t addr; |
| |
| if (ctx) { |
| addr = (uintptr_t)ctx - offsetof(struct toks_driver_ctx_impl,ctx); |
| addr = addr - offsetof(struct toks_driver_ctx_alloc,ctx); |
| ictx = (struct toks_driver_ctx_alloc *)addr; |
| toks_free_driver_ctx_impl(ictx); |
| } |
| } |
| |
| void toks_driver_set_timeout(struct toks_driver_ctx * dctx, int64_t millisecs) |
| { |
| toks_set_driver_timeout(dctx,millisecs); |
| } |
| |
| void toks_driver_unset_timeout(struct toks_driver_ctx * dctx) |
| { |
| toks_set_driver_timeout(dctx,(-1)); |
| } |
| |
| const struct toks_source_version * toks_source_version(void) |
| { |
| return &toks_src_version; |
| } |