diff options
Diffstat (limited to 'src/gpgcedev.c')
-rw-r--r-- | src/gpgcedev.c | 1640 |
1 files changed, 0 insertions, 1640 deletions
diff --git a/src/gpgcedev.c b/src/gpgcedev.c deleted file mode 100644 index c841ec2..0000000 --- a/src/gpgcedev.c +++ /dev/null @@ -1,1640 +0,0 @@ -/* gpgcedrv.c - WindowsCE device driver to implement pipe and syslog. - * Copyright (C) 2010 Free Software Foundation, Inc. - * - * This file is part of Assuan. - * - * Assuan is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. - * - * Assuan is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see <http://www.gnu.org/licenses/>. - * SPDX-License-Identifier: LGPL-3.0+ - */ - -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <windows.h> -#include <devload.h> -#include <winioctl.h> - -/* FIXME Cancel not handled. */ - -#define DBGFILENAME "\\gpgcedev.dbg" -#define LOGFILENAME L"\\gpgcedev.log" -#define GPGCEDEV_KEY_NAME L"Drivers\\GnuPG_Device" -#define GPGCEDEV_KEY_NAME2 L"Drivers\\GnuPG_Log" - - -/* Missing IOCTLs in the current mingw32ce. */ -#ifndef IOCTL_PSL_NOTIFY -# define FILE_DEVICE_PSL 259 -# define IOCTL_PSL_NOTIFY \ - CTL_CODE (259, 255, METHOD_NEITHER, FILE_ANY_ACCESS) -#endif /*IOCTL_PSL_NOTIFY*/ - - -/* The IOCTL to return the rendezvous id of the handle. - - The required outbuf parameter is the address of a variable to store - the rendezvous ID, which is a LONG value. */ -#define GPGCEDEV_IOCTL_GET_RVID \ - CTL_CODE (FILE_DEVICE_STREAMS, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS) - -/* The IOCTL used to create the pipe. - - The caller sends this IOCTL to the read or the write handle. The - required inbuf parameter is address of a variable holding the - rendezvous id of the pipe's other end. There is one possible - problem with the code: If a pipe is kept in non-rendezvous state - until after the rendezvous ids overflow, it is possible that the - wrong end will be used. However this is not a realistic scenario. */ -#define GPGCEDEV_IOCTL_MAKE_PIPE \ - CTL_CODE (FILE_DEVICE_STREAMS, 2049, METHOD_BUFFERED, FILE_ANY_ACCESS) - -/* The IOCTL used to unblock a blocking thread. - - The caller sends this IOCTL to the read or the write handle. No - parameter is required. The effect is that a reader or writer - blocked on the same handle is unblocked (and will return - ERROR_BUSY). Note that the operation can be repeated, if so - desired. The state of the pipe itself will not be affected in any - way. */ -#define GPGCEDEV_IOCTL_UNBLOCK \ - CTL_CODE (FILE_DEVICE_STREAMS, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS) - -/* The IOCTL to assign a rendezvous id to a process. - - The required inbuf parameters are the rendezvous ID to assign and - the process ID of the process receiving the RVID. The handle on - which this is called is not really used at all! */ -#define GPGCEDEV_IOCTL_ASSIGN_RVID \ - CTL_CODE (FILE_DEVICE_STREAMS, 2051, METHOD_BUFFERED, FILE_ANY_ACCESS) - - -/* An object to describe a pipe. */ -struct pipeimpl_s -{ - CRITICAL_SECTION critsect; /* Lock for all members. */ - - int refcnt; - char *buffer; - size_t buffer_size; - size_t buffer_len; /* The valid length of the bufer. */ - size_t buffer_pos; /* The actual read position. */ - -#define PIPE_FLAG_NO_READER 1 -#define PIPE_FLAG_NO_WRITER 2 -#define PIPE_FLAG_UNBLOCK_READER 4 -#define PIPE_FLAG_UNBLOCK_WRITER 8 -#define PIPE_FLAG_HALT_MONITOR 16 - int flags; - - HANDLE space_available; /* Set if space is available. */ - HANDLE data_available; /* Set if data is available. */ - - /* For the monitor thread started by ASSIGN_RVID. */ - HANDLE monitor_proc; - int monitor_access; - LONG monitor_rvid; -}; -typedef struct pipeimpl_s *pipeimpl_t; - - -/* An object to describe a logging context. We can't write directly - to the log stream because we want to do line buffering and thus we - need to store data until we see LF. */ -struct logimpl_s; -typedef struct logimpl_s *logimpl_t; -struct logimpl_s -{ - unsigned long logid; /* An identifier for a log source. */ - unsigned long dsec; /* Tenth of a second since system start. */ - char *line; /* Malloced line buffer. */ - size_t linesize; /* Allocated size of LINE. */ - size_t linelen; /* Used length of the line. */ - int truncated; /* Indicates a truncated log line. */ -}; - - - -/* An object to store information pertaining to an open-context. */ -struct opnctx_s; -typedef struct opnctx_s *opnctx_t; -struct opnctx_s -{ - int inuse; /* True if this object has valid data. */ - int is_log; /* True if this describes a log device. */ - LONG rvid; /* The unique rendezvous identifier. */ - DWORD access_code;/* Value from OpenFile. */ - DWORD share_mode; /* Value from OpenFile. */ - - /* The state shared by all pipe users. Only used if IS_LOG is false. */ - pipeimpl_t pipeimpl; - - /* The state used to implement a log stream. Only used if IS_LOG is true. */ - logimpl_t logimpl; -}; - -/* A malloced table of open-context and the number of allocated slots. */ -static opnctx_t opnctx_table; -static size_t opnctx_table_size; -/* The macros make sure that 0 is never a valid openctx_arg. */ -#define OPNCTX_TO_IDX(ctx_arg) (((ctx_arg) - opnctx_table) + 1) -#define OPNCTX_FROM_IDX(idx) (&opnctx_table[(idx) - 1]) -#define OPNCTX_VALID_IDX_P(idx) ((idx) > 0 && (idx) <= opnctx_table_size) - -typedef struct monitor_s *monitor_t; -struct monitor_s -{ - int inuse; /* True if this object has valid data. */ - pipeimpl_t pipeimpl; -}; -static monitor_t monitor_table; -static size_t monitor_table_size; - -/* A criticial section object used to protect the OPNCTX_TABLE and - MONITOR_TABLE. */ -static CRITICAL_SECTION opnctx_table_cs; - - - -/* A global object to control the logging. */ -struct { - CRITICAL_SECTION lock; /* Lock for this structure. */ - HANDLE filehd; /* Handle of the log output file. */ - int references; /* Number of objects references this one. */ -} logcontrol; - - -/* We don't need a device context for the pipe thus we use the address - of the critical section object for it. */ -#define PIPECTX_VALUE ((DWORD)(&opnctx_table_cs)) - -/* The device context for the log device is the address of our - control structure. */ -#define LOGCTX_VALUE ((DWORD)(&logcontrol)) - - -/* True if we have enabled debugging. */ -static int enable_debug; - -/* True if logging has been enabled. */ -static int enable_logging; - - - -static void -log_debug (const char *fmt, ...) -{ - if (enable_debug) - { - va_list arg_ptr; - FILE *fp; - - fp = fopen (DBGFILENAME, "a+"); - if (!fp) - return; - va_start (arg_ptr, fmt); - vfprintf (fp, fmt, arg_ptr); - va_end (arg_ptr); - fclose (fp); - } -} - - -/* Return a new rendezvous id. We will never return an RVID of 0. */ -static LONG -create_rendezvous_id (void) -{ - static LONG rendezvous_id; - LONG rvid; - - while (!(rvid = InterlockedIncrement (&rendezvous_id))) - ; - return rvid; -} - -/* Return a new log id. These log ids are used to identify log lines - send to the same device; ie. for each CreateFile("GPG2:") a new log - id is assigned. We will ever return a log id of 0. */ -static LONG -create_log_id (void) -{ - static LONG log_id; - LONG lid; - - while (!(lid = InterlockedIncrement (&log_id))) - ; - return lid; -} - - - -pipeimpl_t -pipeimpl_new (void) -{ - pipeimpl_t pimpl; - - pimpl = malloc (sizeof (*pimpl)); - if (!pimpl) - return NULL; - - InitializeCriticalSection (&pimpl->critsect); - pimpl->refcnt = 1; - pimpl->buffer_size = 512; - pimpl->buffer = malloc (pimpl->buffer_size); - if (!pimpl->buffer) - { - DeleteCriticalSection (&pimpl->critsect); - free (pimpl); - return NULL; - } - pimpl->buffer_len = 0; - pimpl->buffer_pos = 0; - pimpl->flags = 0; - pimpl->space_available = CreateEvent (NULL, FALSE, FALSE, NULL); - if (!pimpl->space_available) - { - free (pimpl->buffer); - DeleteCriticalSection (&pimpl->critsect); - free (pimpl); - return NULL; - } - pimpl->data_available = CreateEvent (NULL, FALSE, FALSE, NULL); - if (!pimpl->data_available) - { - CloseHandle (pimpl->space_available); - free (pimpl->buffer); - DeleteCriticalSection (&pimpl->critsect); - free (pimpl); - return NULL; - } - pimpl->monitor_proc = INVALID_HANDLE_VALUE; - pimpl->monitor_access = 0; - pimpl->monitor_rvid = 0; - return pimpl; -} - - -/* PIMPL must be locked. It is unlocked at exit. */ -void -pipeimpl_unref (pipeimpl_t pimpl) -{ - int release = 0; - - if (!pimpl) - return; - - log_debug ("pipeimpl_unref (%p): dereference\n", pimpl); - - if (--pimpl->refcnt == 0) - release = 1; - LeaveCriticalSection (&pimpl->critsect); - - if (! release) - return; - - log_debug ("pipeimpl_unref (%p): release\n", pimpl); - - DeleteCriticalSection (&pimpl->critsect); - if (pimpl->buffer) - { - free (pimpl->buffer); - pimpl->buffer = NULL; - pimpl->buffer_size = 0; - } - if (pimpl->space_available != INVALID_HANDLE_VALUE) - { - CloseHandle (pimpl->space_available); - pimpl->space_available = INVALID_HANDLE_VALUE; - } - if (pimpl->data_available != INVALID_HANDLE_VALUE) - { - CloseHandle (pimpl->data_available); - pimpl->data_available = INVALID_HANDLE_VALUE; - } -} - - - -/* Allocate a new log structure. */ -logimpl_t -logimpl_new (void) -{ - logimpl_t limpl; - - limpl = calloc (1, sizeof *limpl); - if (!limpl) - return NULL; - limpl->logid = create_log_id (); - limpl->linesize = 256; - limpl->line = malloc (limpl->linesize); - if (!limpl->line) - { - free (limpl); - return NULL; - } - - return limpl; -} - - -/* There is no need to lock LIMPL, thus is a dummy function. */ -void -logimpl_unref (logimpl_t limpl) -{ - (void)limpl; -} - - -/* Flush a pending log line. */ -static void -logimpl_flush (logimpl_t limpl) -{ - if (!limpl->linelen || !enable_logging) - return; - - EnterCriticalSection (&logcontrol.lock); - if (logcontrol.filehd == INVALID_HANDLE_VALUE) - logcontrol.filehd = CreateFile (LOGFILENAME, GENERIC_WRITE, - FILE_SHARE_READ, - NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, NULL); - if (!logcontrol.filehd) - log_debug ("can't open log file: rc=%d\n", (int)GetLastError ()); - else - { - char buf[50]; - DWORD nwritten; - - snprintf (buf, sizeof buf, - "%06lu/%lu//", limpl->dsec % 1000000, limpl->logid); - if (!WriteFile (logcontrol.filehd, buf, strlen (buf), &nwritten, NULL)) - log_debug ("error writing log file: rc=%d\n", (int)GetLastError ()); - else if (!WriteFile (logcontrol.filehd, - limpl->line, limpl->linelen, &nwritten, NULL)) - log_debug ("error writing log file: rc=%d\n", (int)GetLastError ()); - - snprintf (buf, sizeof buf, "%s\n", limpl->truncated? "[...]":""); - if (!WriteFile (logcontrol.filehd, buf, strlen (buf), &nwritten, NULL)) - log_debug ("error writing log file: rc=%d\n", (int)GetLastError ()); - } - - LeaveCriticalSection (&logcontrol.lock); - limpl->linelen = 0; - limpl->truncated = 0; -} - - -/* Return a new opnctx handle and mark it as used. Returns NULL and - sets LastError on memory failure etc. opnctx_table_cs must be - locked on entry and is locked on exit. Note that the returned - pointer is only valid as long as opnctx_table_cs stays locked, as - it is not stable under table reallocation. */ -static opnctx_t -allocate_opnctx (int is_log) -{ - opnctx_t opnctx = NULL; - int idx; - - for (idx = 0; idx < opnctx_table_size; idx++) - if (! opnctx_table[idx].inuse) - break; - if (idx == opnctx_table_size) - { - /* We need to increase the size of the table. The approach we - take is straightforward to minimize the risk of bugs. */ - opnctx_t newtbl; - size_t newsize = opnctx_table_size + 64; - - newtbl = calloc (newsize, sizeof *newtbl); - if (!newtbl) - goto leave; - memcpy (newtbl, opnctx_table, opnctx_table_size * sizeof (*newtbl)); - free (opnctx_table); - opnctx_table = newtbl; - idx = opnctx_table_size; - opnctx_table_size = newsize; - } - opnctx = &opnctx_table[idx]; - opnctx->inuse = 1; - opnctx->is_log = is_log; - opnctx->rvid = 0; - opnctx->access_code = 0; - opnctx->share_mode = 0; - opnctx->pipeimpl = 0; - opnctx->logimpl = 0; - - leave: - return opnctx; -} - - -/* Verify context CTX, returns NULL if not valid and the pointer to - the context if valid. opnctx_table_cs must be locked on entry and - is locked on exit. Note that the returned pointer is only valid as - long as opnctx_table_cs remains locked. */ -opnctx_t -verify_opnctx (DWORD ctx_arg) -{ - opnctx_t ctx; - - if (! OPNCTX_VALID_IDX_P (ctx_arg)) - { - SetLastError (ERROR_INVALID_HANDLE); - return NULL; - } - ctx = OPNCTX_FROM_IDX (ctx_arg); - - if (! ctx->inuse) - { - SetLastError (ERROR_INVALID_HANDLE); - return NULL; - } - return ctx; -} - - -/* Return a new monitor handle and mark it as used. Returns NULL and - sets LastError on memory failure etc. opnctx_table_cs must be - locked on entry and is locked on exit. Note that the returned - pointer is only valid as long as opnctx_table_cs stays locked, as - it is not stable under table reallocation. */ -static monitor_t -allocate_monitor (void) -{ - monitor_t monitor = NULL; - int idx; - - for (idx = 0; idx < monitor_table_size; idx++) - if (! monitor_table[idx].inuse) - break; - if (idx == monitor_table_size) - { - /* We need to increase the size of the table. The approach we - take is straightforward to minimize the risk of bugs. */ - monitor_t newtbl; - size_t newsize = monitor_table_size + 16; - - newtbl = calloc (newsize, sizeof *newtbl); - if (!newtbl) - goto leave; - memcpy (newtbl, monitor_table, monitor_table_size * sizeof (*newtbl)); - free (monitor_table); - monitor_table = newtbl; - idx = monitor_table_size; - monitor_table_size = newsize; - } - monitor = &monitor_table[idx]; - monitor->inuse = 1; - monitor->pipeimpl = 0; - - leave: - return monitor; -} - - -static pipeimpl_t -assert_pipeimpl (opnctx_t ctx) -{ - DWORD ctx_arg = OPNCTX_TO_IDX (ctx); - - if (ctx->is_log) - { - log_debug (" assert_pipeimpl (ctx=%i): " - "error: not valid for a log device\n", ctx_arg); - return NULL; - } - if (! ctx->pipeimpl) - { - ctx->pipeimpl = pipeimpl_new (); - if (! ctx->pipeimpl) - { - log_debug (" assert_pipeimpl (ctx=%i): error: can't create pipe\n", - ctx_arg); - return NULL; - } - log_debug (" assert_pipeimpl (ctx=%i): created pipe 0x%p\n", - ctx_arg, ctx->pipeimpl); - } - return ctx->pipeimpl; -} - - -static logimpl_t -assert_logimpl (opnctx_t ctx) -{ - DWORD ctx_arg = OPNCTX_TO_IDX (ctx); - - if (!ctx->is_log) - { - log_debug (" assert_logimpl (ctx=%i): " - "error: not valid for a pipe device\n", ctx_arg); - return NULL; - } - if (!ctx->logimpl) - { - ctx->logimpl = logimpl_new (); - if (!ctx->logimpl) - { - log_debug (" assert_logimpl (ctx=%i): error: can't create log\n", - ctx_arg); - return NULL; - } - log_debug (" assert_logimpl (ctx=%i): created log 0x%p\n", - ctx_arg, ctx->logimpl); - } - return ctx->logimpl; -} - - -/* Verify access CODE for context CTX_ARG, returning a reference to - the locked pipe or the locked log implementation. opnctx_table_cs - must be unlocked on entry and is unlocked on exit. */ -int -access_opnctx (DWORD ctx_arg, DWORD code, pipeimpl_t *r_pipe, logimpl_t *r_log) -{ - opnctx_t ctx; - - *r_pipe = NULL; - *r_log = NULL; - - EnterCriticalSection (&opnctx_table_cs); - ctx = verify_opnctx (ctx_arg); - if (! ctx) - { - /* Error is set by verify_opnctx. */ - LeaveCriticalSection (&opnctx_table_cs); - return -1; - } - - if (! (ctx->access_code & code)) - { - SetLastError (ERROR_INVALID_ACCESS); - LeaveCriticalSection (&opnctx_table_cs); - return -1; - } - - if (ctx->is_log) - { - logimpl_t limpl; - - limpl = assert_logimpl (ctx); - if (!limpl) - { - LeaveCriticalSection (&opnctx_table_cs); - return -1; - } - *r_log = limpl; - } - else - { - pipeimpl_t pimpl; - - pimpl = assert_pipeimpl (ctx); - if (! pimpl) - { - LeaveCriticalSection (&opnctx_table_cs); - return -1; - } - EnterCriticalSection (&pimpl->critsect); - pimpl->refcnt++; - *r_pipe = pimpl; - } - - LeaveCriticalSection (&opnctx_table_cs); - return 0; -} - - - -static char * -wchar_to_utf8 (const wchar_t *string) -{ - int n; - size_t length = wcslen (string); - char *result; - - n = WideCharToMultiByte (CP_UTF8, 0, string, length, NULL, 0, NULL, NULL); - if (n < 0 || (n+1) <= 0) - abort (); - - result = malloc (n+1); - if (!result) - abort (); - n = WideCharToMultiByte (CP_ACP, 0, string, length, result, n, NULL, NULL); - if (n < 0) - abort (); - - result[n] = 0; - return result; -} - - -/* Initialize the device and return a device specific context. */ -DWORD -GPG_Init (LPCTSTR active_key, DWORD bus_context) -{ - static int firsttimedone; - HKEY handle; - wchar_t buffer[25]; - DWORD buflen; - DWORD result; - - (void)bus_context; - - EnterCriticalSection (&logcontrol.lock); - if (!firsttimedone) - { - firsttimedone++; - if (!RegOpenKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME, - 0, KEY_READ, &handle)) - { - buflen = sizeof buffer; - if (!RegQueryValueEx (handle, L"debugDriver", 0, NULL, - (PBYTE)buffer, &buflen) - && wcstol (buffer, NULL, 10) > 0) - enable_debug = 1; - RegCloseKey (handle); - } - if (!RegOpenKeyEx (HKEY_LOCAL_MACHINE, GPGCEDEV_KEY_NAME2, - 0, KEY_READ, &handle)) - { - buflen = sizeof buffer; - if (!RegQueryValueEx (handle, L"enableLog", 0, NULL, - (PBYTE)buffer, &buflen) - && wcstol (buffer, NULL, 10) > 0) - enable_logging = 1; - RegCloseKey (handle); - } - } - LeaveCriticalSection (&logcontrol.lock); - - if (enable_debug) - { - char *tmpbuf; - tmpbuf = wchar_to_utf8 (active_key); - log_debug ("GPG_Init (%s)\n", tmpbuf); - free (tmpbuf); - } - - if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, active_key, 0, KEY_READ, &handle)) - { - log_debug ("GPG_Init: error reading registry: rc=%d\n", - (int)GetLastError ()); - return 0; - } - - buflen = sizeof buffer; - if (RegQueryValueEx (handle, L"Name", 0, NULL, (PBYTE)buffer, &buflen)) - { - log_debug ("GPG_Init: error reading registry value 'Name': rc=%d\n", - (int)GetLastError ()); - result = 0; - } - else if (!wcscmp (buffer, L"GPG1:")) - { - /* This is the pipe device: We don't need any global data. - However, we need to return something. */ - log_debug ("GPG_Init: created pipe device (devctx=%p)\n", PIPECTX_VALUE); - result = PIPECTX_VALUE; - } - else if (!wcscmp (buffer, L"GPG2:")) - { - /* This is the log device. Clear the object and return something. */ - logcontrol.filehd = INVALID_HANDLE_VALUE; - log_debug ("GPG_Init: created log device (devctx=%p)\n", 0); - result = LOGCTX_VALUE; - } - else - { - if (enable_debug) - { - char *tmpbuf; - tmpbuf = wchar_to_utf8 (buffer); - log_debug ("GPG_Init: device '%s' is not supported\n", tmpbuf); - free (tmpbuf); - } - SetLastError (ERROR_DEV_NOT_EXIST); - result = 0; - } - - RegCloseKey (handle); - return result; -} - - - -/* Deinitialize this device driver. */ -BOOL -GPG_Deinit (DWORD devctx) -{ - log_debug ("GPG_Deinit (devctx=0x%p)\n", (void*)devctx); - if (devctx == PIPECTX_VALUE) - { - /* No need to release resources. */ - } - else if (devctx == LOGCTX_VALUE) - { - EnterCriticalSection (&logcontrol.lock); - if (logcontrol.filehd != INVALID_HANDLE_VALUE) - { - CloseHandle (logcontrol.filehd); - logcontrol.filehd = INVALID_HANDLE_VALUE; - } - LeaveCriticalSection (&logcontrol.lock); - } - else - { - SetLastError (ERROR_INVALID_PARAMETER); - return FALSE; /* Error. */ - } - - return TRUE; /* Success. */ -} - - - -/* Create a new open context. This function is called due to a - CreateFile from the application. */ -DWORD -GPG_Open (DWORD devctx, DWORD access_code, DWORD share_mode) -{ - opnctx_t opnctx; - DWORD ctx_arg = 0; - int is_log; - - log_debug ("GPG_Open (devctx=%p)\n", (void*)devctx); - if (devctx == PIPECTX_VALUE) - is_log = 0; - else if (devctx == LOGCTX_VALUE) - is_log = 1; - else - { - log_debug ("GPG_Open (devctx=%p): error: wrong devctx (expected 0x%p)\n", - (void*) devctx); - SetLastError (ERROR_INVALID_PARAMETER); - return 0; /* Error. */ - } - - EnterCriticalSection (&opnctx_table_cs); - opnctx = allocate_opnctx (is_log); - if (!opnctx) - { - log_debug ("GPG_Open (devctx=%p): error: could not allocate context\n", - (void*) devctx); - goto leave; - } - - opnctx->access_code = access_code; - opnctx->share_mode = share_mode; - - ctx_arg = OPNCTX_TO_IDX (opnctx); - - log_debug ("GPG_Open (devctx=%p, is_log=%d): success: created context %i\n", - (void*) devctx, is_log, ctx_arg); - if (is_log) - { - EnterCriticalSection (&logcontrol.lock); - logcontrol.references++; - LeaveCriticalSection (&logcontrol.lock); - } - - leave: - LeaveCriticalSection (&opnctx_table_cs); - return ctx_arg; -} - - - -BOOL -GPG_Close (DWORD opnctx_arg) -{ - opnctx_t opnctx; - BOOL result = FALSE; - - log_debug ("GPG_Close (ctx=%i)\n", opnctx_arg); - - EnterCriticalSection (&opnctx_table_cs); - opnctx = verify_opnctx (opnctx_arg); - if (!opnctx) - { - log_debug ("GPG_Close (ctx=%i): could not find context\n", opnctx_arg); - goto leave; - } - - if (opnctx->pipeimpl) - { - pipeimpl_t pimpl = opnctx->pipeimpl; - EnterCriticalSection (&pimpl->critsect); - /* This needs to be adjusted if there can be multiple - reader/writers. */ - if (opnctx->access_code & GENERIC_READ) - { - pimpl->flags |= PIPE_FLAG_NO_READER; - SetEvent (pimpl->space_available); - } - else if (opnctx->access_code & GENERIC_WRITE) - { - pimpl->flags |= PIPE_FLAG_NO_WRITER; - SetEvent (pimpl->data_available); - } - pipeimpl_unref (pimpl); - opnctx->pipeimpl = 0; - } - if (opnctx->logimpl) - { - logimpl_t limpl = opnctx->logimpl; - - logimpl_flush (limpl); - logimpl_unref (limpl); - free (limpl->line); - free (limpl); - opnctx->logimpl = 0; - EnterCriticalSection (&logcontrol.lock); - logcontrol.references--; - if (!logcontrol.references && logcontrol.filehd) - { - CloseHandle (logcontrol.filehd); - logcontrol.filehd = INVALID_HANDLE_VALUE; - } - LeaveCriticalSection (&logcontrol.lock); - } - opnctx->access_code = 0; - opnctx->share_mode = 0; - opnctx->rvid = 0; - opnctx->inuse = 0; - result = TRUE; - log_debug ("GPG_Close (ctx=%i): success\n", opnctx_arg); - - leave: - LeaveCriticalSection (&opnctx_table_cs); - return result; -} - - - -DWORD -GPG_Read (DWORD opnctx_arg, void *buffer, DWORD count) -{ - pipeimpl_t pimpl; - logimpl_t limpl; - const char *src; - char *dst; - int result = -1; - - log_debug ("GPG_Read (ctx=%i, buffer=0x%p, count=%d)\n", - opnctx_arg, buffer, count); - - if (access_opnctx (opnctx_arg, GENERIC_READ, &pimpl, &limpl)) - { - log_debug ("GPG_Read (ctx=%i): error: could not access context\n", - opnctx_arg); - return -1; - } - - if (limpl) - { - /* Reading from a log stream does not make sense. Return EOF. */ - result = 0; - goto leave; - } - - retry: - if (pimpl->buffer_pos == pimpl->buffer_len) - { - HANDLE data_available = pimpl->data_available; - - /* Check for end of file. */ - if (pimpl->flags & PIPE_FLAG_NO_WRITER) - { - log_debug ("GPG_Read (ctx=%i): success: EOF\n", opnctx_arg); - result = 0; - goto leave; - } - - /* Check for request to unblock once. */ - if (pimpl->flags & PIPE_FLAG_UNBLOCK_READER) - { - log_debug ("GPG_Read (ctx=%i): success: EBUSY (due to unblock)\n", - opnctx_arg); - pimpl->flags &= ~PIPE_FLAG_UNBLOCK_READER; - SetLastError (ERROR_BUSY); - result = -1; - goto leave; - } - - LeaveCriticalSection (&pimpl->critsect); - log_debug ("GPG_Read (ctx=%i): waiting: data_available\n", opnctx_arg); - WaitForSingleObject (data_available, INFINITE); - log_debug ("GPG_Read (ctx=%i): resuming: data_available\n", opnctx_arg); - EnterCriticalSection (&pimpl->critsect); - goto retry; - } - - dst = buffer; - src = pimpl->buffer + pimpl->buffer_pos; - while (count > 0 && pimpl->buffer_pos < pimpl->buffer_len) - { - *dst++ = *src++; - count--; - pimpl->buffer_pos++; - } - result = (dst - (char*)buffer); - if (pimpl->buffer_pos == pimpl->buffer_len) - pimpl->buffer_pos = pimpl->buffer_len = 0; - - /* Now there should be some space available. Signal the write end. - Even if COUNT was passed as NULL and no space is available, - signaling must be done. */ - if (!SetEvent (pimpl->space_available)) - log_debug ("GPG_Read (ctx=%i): warning: SetEvent(space_available) " - "failed: rc=%d\n", opnctx_arg, (int)GetLastError ()); - - log_debug ("GPG_Read (ctx=%i): success: result=%d\n", opnctx_arg, result); - - leave: - pipeimpl_unref (pimpl); - logimpl_unref (limpl); - return result; -} - - - -DWORD -GPG_Write (DWORD opnctx_arg, const void *buffer, DWORD count) -{ - pipeimpl_t pimpl; - logimpl_t limpl; - int result = -1; - const char *src; - char *dst; - size_t nwritten = 0; - - log_debug ("GPG_Write (ctx=%i, buffer=0x%p, count=%d)\n", opnctx_arg, - buffer, count); - - if (access_opnctx (opnctx_arg, GENERIC_WRITE, &pimpl, &limpl)) - { - log_debug ("GPG_Write (ctx=%i): error: could not access context\n", - opnctx_arg); - return -1; - } - - if (!count) - { - log_debug ("GPG_Write (ctx=%i): success\n", opnctx_arg); - result = 0; - goto leave; - } - - retry: - if (limpl) - { - /* Store it in our buffer up to a LF and print complete lines. */ - result = count; - if (!limpl->linelen) - limpl->dsec = GetTickCount () / 100; - dst = limpl->line + limpl->linelen; - for (src = buffer; count; count--, src++) - { - if (*src == '\n') - { - logimpl_flush (limpl); - dst = limpl->line + limpl->linelen; - } - else if (limpl->linelen >= limpl->linesize) - limpl->truncated = 1; - else - { - *dst++ = *src; - limpl->linelen++; - } - } - } - else /* pimpl */ - { - /* Check for broken pipe. */ - if (pimpl->flags & PIPE_FLAG_NO_READER) - { - log_debug ("GPG_Write (ctx=%i): error: broken pipe\n", opnctx_arg); - SetLastError (ERROR_BROKEN_PIPE); - goto leave; - } - - /* Check for request to unblock once. */ - if (pimpl->flags & PIPE_FLAG_UNBLOCK_WRITER) - { - log_debug ("GPG_Write (ctx=%i): success: EBUSY (due to unblock)\n", - opnctx_arg); - pimpl->flags &= ~PIPE_FLAG_UNBLOCK_WRITER; - SetLastError (ERROR_BUSY); - result = -1; - goto leave; - } - - /* Write to our buffer. */ - if (pimpl->buffer_len == pimpl->buffer_size) - { - /* Buffer is full. */ - HANDLE space_available = pimpl->space_available; - LeaveCriticalSection (&pimpl->critsect); - log_debug ("GPG_Write (ctx=%i): waiting: space_available\n", - opnctx_arg); - WaitForSingleObject (space_available, INFINITE); - log_debug ("GPG_Write (ctx=%i): resuming: space_available\n", - opnctx_arg); - EnterCriticalSection (&pimpl->critsect); - goto retry; - } - - src = buffer; - dst = pimpl->buffer + pimpl->buffer_len; - while (count > 0 && pimpl->buffer_len < pimpl->buffer_size) - { - *dst++ = *src++; - count--; - pimpl->buffer_len++; - nwritten++; - } - result = nwritten; - - if (!SetEvent (pimpl->data_available)) - log_debug ("GPG_Write (ctx=%i): warning: SetEvent(data_available) " - "failed: rc=%d\n", opnctx_arg, (int)GetLastError ()); - } - - log_debug ("GPG_Write (ctx=%i): success: result=%d\n", opnctx_arg, result); - - leave: - pipeimpl_unref (pimpl); - logimpl_unref (limpl); - return result; -} - - - -DWORD -GPG_Seek (DWORD opnctx_arg, long amount, WORD type) -{ - SetLastError (ERROR_SEEK_ON_DEVICE); - return -1; /* Error. */ -} - - - -/* opnctx_table_s is locked on entering and on exit. */ -static BOOL -make_pipe (opnctx_t ctx, LONG rvid) -{ - DWORD ctx_arg = OPNCTX_TO_IDX (ctx); - opnctx_t peerctx = NULL; - int idx; - pipeimpl_t pimpl; - - log_debug (" make_pipe (ctx=%i, rvid=%08lx)\n", ctx_arg, rvid); - - if (ctx->pipeimpl) - { - log_debug (" make_pipe (ctx=%i): error: already assigned\n", ctx_arg); - SetLastError (ERROR_ALREADY_ASSIGNED); - return FALSE; - } - - /* GnuPG and other programs don't use the safe ASSIGN_RVID call - because they guarantee that the context exists during the whole - time the child process runs. GPGME is more asynchronous and - relies on ASSIGN_RVID monitors. So, first check for open - contexts, then check for monitors. */ - - for (idx = 0; idx < opnctx_table_size; idx++) - if (opnctx_table[idx].inuse && opnctx_table[idx].rvid == rvid) - { - peerctx = &opnctx_table[idx]; - break; - } - if (peerctx) - { - /* This is the GnuPG etc case, where the context is still open. - It may also cover the GPGME case if GPGME is still using its - own end of the pipe at the time of this call. */ - if (peerctx == ctx) - { - log_debug (" make_pipe (ctx=%i): error: target and source identical\n", - ctx_arg); - SetLastError (ERROR_INVALID_TARGET_HANDLE); - return FALSE; - } - - if ((ctx->access_code & GENERIC_READ)) - { - /* Check that the peer is a write end. */ - if (!(peerctx->access_code & GENERIC_WRITE)) - { - log_debug (" make_pipe (ctx=%i): error: peer is not writer\n", - ctx_arg); - SetLastError (ERROR_INVALID_ACCESS); - return FALSE; - } - } - else if ((ctx->access_code & GENERIC_WRITE)) - { - /* Check that the peer is a read end. */ - if (!(peerctx->access_code & GENERIC_READ)) - { - log_debug (" make_pipe (ctx=%i): error: peer is not reader\n", - ctx_arg); - SetLastError (ERROR_INVALID_ACCESS); - return FALSE; - } - } - else - { - log_debug (" make_pipe (ctx=%i): error: invalid access\n", ctx_arg); - SetLastError (ERROR_INVALID_ACCESS); - return FALSE; - } - - /* Make sure the peer has a pipe implementation to be shared. If - not yet, create one. */ - pimpl = assert_pipeimpl (peerctx); - if (! pimpl) - return FALSE; - } - else - { - /* This is the case where ASSIGN_RVID was called to create a - monitor, and the pipe is already closed at the parent side. - For example GPGME verify detached plain text, where GPG calls - MAKE_PIPE very late. */ - - for (idx = 0; idx < monitor_table_size; idx++) - if (monitor_table[idx].inuse - && monitor_table[idx].pipeimpl->monitor_rvid == rvid) - { - pimpl = monitor_table[idx].pipeimpl; - break; - } - if (idx == monitor_table_size) - { - log_debug (" make_pipe (ctx=%i): error: not found\n", ctx_arg); - SetLastError (ERROR_NOT_FOUND); - return FALSE; - } - - if (ctx->access_code & GENERIC_READ) - { - /* Check that the peer is a write end. */ - if (!(pimpl->monitor_access & GENERIC_READ)) - { - log_debug (" make_pipe (ctx=%i): error: monitor is not reader\n", - ctx_arg); - SetLastError (ERROR_INVALID_ACCESS); - return FALSE; - } - } - else if ((ctx->access_code & GENERIC_WRITE)) - { - /* Check that the peer is a read end. */ - if (!(pimpl->monitor_access & GENERIC_WRITE)) - { - log_debug (" make_pipe (ctx=%i): error: monitor is not writer\n", - ctx_arg); - SetLastError (ERROR_INVALID_ACCESS); - return FALSE; - } - } - else - { - log_debug (" make_pipe (ctx=%i): error: invalid access\n", ctx_arg); - SetLastError (ERROR_INVALID_ACCESS); - return FALSE; - } - } - - EnterCriticalSection (&pimpl->critsect); - pimpl->refcnt++; - if (pimpl->monitor_proc != INVALID_HANDLE_VALUE) - { - /* If there is a monitor to the pipe, then it's now about time - to ask it to go away. */ - log_debug (" make_pipe (ctx=%i): waking up monitor for pipe 0x%p\n", - ctx_arg, pimpl); - pimpl->flags |= PIPE_FLAG_HALT_MONITOR; - if (pimpl->monitor_access & GENERIC_READ) - SetEvent (pimpl->data_available); - else - SetEvent (pimpl->space_available); - } - LeaveCriticalSection (&pimpl->critsect); - - ctx->pipeimpl = pimpl; - - if (peerctx) - { - log_debug (" make_pipe (ctx=%i): success: combined with peer ctx=%i " - "(pipe 0x%p)\n", ctx_arg, OPNCTX_TO_IDX (peerctx), pimpl); - } - else - { - log_debug (" make_pipe (ctx=%i): success: combined with " - "pipe 0x%p\n", ctx_arg, OPNCTX_TO_IDX (peerctx), pimpl); - } - - return TRUE; -} - - -/* opnctx_table_s is locked on entering and on exit. */ -static BOOL -unblock_call (opnctx_t ctx) -{ - /* If there is no pipe object, no thread can be blocked. */ - if (!ctx->pipeimpl) - return TRUE; - - EnterCriticalSection (&ctx->pipeimpl->critsect); - if (ctx->access_code & GENERIC_READ) - { - ctx->pipeimpl->flags |= PIPE_FLAG_UNBLOCK_READER; - SetEvent (ctx->pipeimpl->data_available); - } - else if (ctx->access_code & GENERIC_WRITE) - { - ctx->pipeimpl->flags |= PIPE_FLAG_UNBLOCK_WRITER; - SetEvent (ctx->pipeimpl->space_available); - } - LeaveCriticalSection (&ctx->pipeimpl->critsect); - - return TRUE; -} - - -static DWORD CALLBACK -monitor_main (void *arg) -{ - pipeimpl_t pimpl = (pipeimpl_t) arg; - HANDLE handles[2]; - int idx; - - log_debug ("starting monitor (pimpl=0x%p)\n", pimpl); - - EnterCriticalSection (&pimpl->critsect); - /* Putting proc first in the array is convenient, as this is a hard - break-out condition (and thus takes precedence in WFMO). The - reader/writer event is a soft condition, which also requires a - flag to be set. */ - handles[0] = pimpl->monitor_proc; - if (pimpl->monitor_access & GENERIC_READ) - handles[1] = pimpl->data_available; - else - handles[1] = pimpl->space_available; - - retry: - /* First check if the peer has not gone away. If it has, we are done. */ - if (pimpl->flags & PIPE_FLAG_HALT_MONITOR) - { - log_debug ("monitor (pimpl=0x%p): done: monitored process taking over\n", - pimpl); - } - else - { - DWORD res; - - LeaveCriticalSection (&pimpl->critsect); - log_debug ("monitor (pimpl=0x%p): waiting\n", pimpl); - res = WaitForMultipleObjects (2, handles, FALSE, INFINITE); - log_debug ("monitor (pimpl=0x%p): resuming\n", pimpl); - EnterCriticalSection (&pimpl->critsect); - - if (res == WAIT_FAILED) - { - log_debug ("monitor (pimpl=0x%p): WFMO failed: %i\n", - pimpl, GetLastError ()); - } - else if (res == WAIT_OBJECT_0) - { - log_debug ("monitor (pimpl=0x%p): done: monitored process died\n", - pimpl); - } - else if (res == WAIT_OBJECT_0 + 1) - goto retry; - else - { - log_debug ("monitor (pimpl=0x%p): unexpected result of WFMO: %i\n", - pimpl, res); - } - } - - log_debug ("ending monitor (pimpl=0x%p)\n", pimpl); - - /* Remove the monitor from the monitor table. */ - LeaveCriticalSection (&pimpl->critsect); - EnterCriticalSection (&opnctx_table_cs); - for (idx = 0; idx < monitor_table_size; idx++) - if (monitor_table[idx].inuse - && monitor_table[idx].pipeimpl == pimpl) - { - monitor_table[idx].pipeimpl = NULL; - monitor_table[idx].inuse = 0; - break; - } - if (idx == monitor_table_size) - log_debug ("can not find monitor in table (pimpl=0x%p)\n", pimpl); - LeaveCriticalSection (&opnctx_table_cs); - EnterCriticalSection (&pimpl->critsect); - - /* Now do the rest of the cleanup. */ - CloseHandle (pimpl->monitor_proc); - pimpl->monitor_proc = INVALID_HANDLE_VALUE; - pimpl->monitor_access = 0; - pimpl->monitor_rvid = 0; - pimpl->flags &= ~PIPE_FLAG_HALT_MONITOR; - pipeimpl_unref (pimpl); - - return 0; -} - - -/* opnctx_table_s is locked on entering and on exit. */ -static BOOL -assign_rvid (opnctx_t ctx, DWORD rvid, DWORD pid) -{ - DWORD ctx_arg = OPNCTX_TO_IDX (ctx); - int idx; - opnctx_t peerctx; - HANDLE monitor_hnd; - HANDLE proc; - pipeimpl_t pimpl; - monitor_t monitor; - - log_debug (" assign_rvid (ctx=%i, rvid=%08lx, pid=%08lx)\n", - ctx_arg, rvid, pid); - - for (idx = 0; idx < opnctx_table_size; idx++) - if (opnctx_table[idx].inuse && opnctx_table[idx].rvid == rvid) - { - peerctx = &opnctx_table[idx]; - break; - } - if (! peerctx) - { - log_debug (" assign_rvid (ctx=%i): error: not found\n", ctx_arg); - SetLastError (ERROR_NOT_FOUND); - return FALSE; - } - - if (peerctx->pipeimpl - && peerctx->pipeimpl->monitor_proc != INVALID_HANDLE_VALUE) - { - log_debug (" assign_rvid (ctx=%i): error: rvid already assigned\n", - ctx_arg); - SetLastError (ERROR_ALREADY_ASSIGNED); - return FALSE; - } - - proc = OpenProcess (0, FALSE, pid); - if (proc == NULL) - { - log_debug (" assign_rvid (ctx=%i): error: process not found\n", - ctx_arg); - return FALSE; - } - - /* Acquire a reference to the pipe. We don't want accesss to be - checked. */ - pimpl = assert_pipeimpl (peerctx); - if (! pimpl) - { - CloseHandle (proc); - return FALSE; - } - - monitor = allocate_monitor (); - if (!monitor) - { - log_debug (" assign_rvid (ctx=%i): error: could not allocate monitor\n", - ctx_arg); - CloseHandle (proc); - return FALSE; - } - monitor->pipeimpl = pimpl; - - EnterCriticalSection (&pimpl->critsect); - pimpl->refcnt++; - - /* The monitor shadows the peer, so it takes its access. Our access - is the opposite of that of the peer. */ - pimpl->monitor_proc = proc; - if (peerctx->access_code == GENERIC_READ) - pimpl->monitor_access = GENERIC_WRITE; - else - pimpl->monitor_access = GENERIC_READ; - pimpl->monitor_rvid = rvid; - - monitor_hnd = CreateThread (NULL, 0, monitor_main, pimpl, 0, NULL); - if (monitor_hnd == INVALID_HANDLE_VALUE) - { - pimpl->monitor_access = 0; - pimpl->monitor_proc = INVALID_HANDLE_VALUE; - LeaveCriticalSection (&pimpl->critsect); - - monitor->pipeimpl = NULL; - monitor->inuse = 0; - - CloseHandle (proc); - log_debug (" assign_rvid (ctx=%i): error: can not create monitor\n", - ctx_arg); - return FALSE; - } - CloseHandle (monitor_hnd); - - /* Consume the pimpl reference. */ - LeaveCriticalSection (&pimpl->critsect); - - return TRUE; -} - - -BOOL -GPG_IOControl (DWORD opnctx_arg, DWORD code, void *inbuf, DWORD inbuflen, - void *outbuf, DWORD outbuflen, DWORD *actualoutlen) -{ - opnctx_t opnctx; - BOOL result = FALSE; - LONG rvid; - LONG pid; - - log_debug ("GPG_IOControl (ctx=%i, %08x)\n", opnctx_arg, code); - - EnterCriticalSection (&opnctx_table_cs); - opnctx = verify_opnctx (opnctx_arg); - if (!opnctx) - { - log_debug ("GPG_IOControl (ctx=%i): error: could not access context\n", - opnctx_arg); - goto leave; - } - if (opnctx->is_log) - { - log_debug ("GPG_IOControl (ctx=%i): error: invalid code %u" - " for log device\n", opnctx_arg, (unsigned int)code); - SetLastError (ERROR_INVALID_PARAMETER); - goto leave; - } - - switch (code) - { - case GPGCEDEV_IOCTL_GET_RVID: - log_debug ("GPG_IOControl (ctx=%i): code: GET_RVID\n", opnctx_arg); - if (inbuf || inbuflen || !outbuf || outbuflen < sizeof (LONG)) - { - log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n", - opnctx_arg); - SetLastError (ERROR_INVALID_PARAMETER); - goto leave; - } - - if (! opnctx->rvid) - opnctx->rvid = create_rendezvous_id (); - log_debug ("GPG_IOControl (ctx=%i): returning rvid: %08lx\n", - opnctx_arg, opnctx->rvid); - - memcpy (outbuf, &opnctx->rvid, sizeof (LONG)); - if (actualoutlen) - *actualoutlen = sizeof (LONG); - result = TRUE; - break; - - case GPGCEDEV_IOCTL_MAKE_PIPE: - log_debug ("GPG_IOControl (ctx=%i): code: MAKE_PIPE\n", opnctx_arg); - if (!inbuf || inbuflen < sizeof (LONG) - || outbuf || outbuflen || actualoutlen) - { - log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n", - opnctx_arg); - SetLastError (ERROR_INVALID_PARAMETER); - goto leave; - } - memcpy (&rvid, inbuf, sizeof (LONG)); - log_debug ("GPG_IOControl (ctx=%i): make pipe for rvid: %08lx\n", - opnctx_arg, rvid); - if (make_pipe (opnctx, rvid)) - result = TRUE; - break; - - case GPGCEDEV_IOCTL_UNBLOCK: - log_debug ("GPG_IOControl (ctx=%i): code: UNBLOCK\n", opnctx_arg); - if (inbuf || inbuflen || outbuf || outbuflen || actualoutlen) - { - log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n", - opnctx_arg); - SetLastError (ERROR_INVALID_PARAMETER); - goto leave; - } - - if (unblock_call (opnctx)) - result = TRUE; - break; - - case GPGCEDEV_IOCTL_ASSIGN_RVID: - log_debug ("GPG_IOControl (ctx=%i): code: ASSIGN_RVID\n", opnctx_arg); - if (!inbuf || inbuflen < 2 * sizeof (DWORD) - || outbuf || outbuflen || actualoutlen) - { - log_debug ("GPG_IOControl (ctx=%i): error: invalid parameter\n", - opnctx_arg); - SetLastError (ERROR_INVALID_PARAMETER); - goto leave; - } - memcpy (&rvid, inbuf, sizeof (DWORD)); - memcpy (&pid, ((char *) inbuf) + sizeof (DWORD), sizeof (DWORD)); - log_debug ("GPG_IOControl (ctx=%i): assign rvid %08lx to pid %08lx\n", - opnctx_arg, rvid, pid); - if (assign_rvid (opnctx, rvid, pid)) - result = TRUE; - break; - - case IOCTL_PSL_NOTIFY: - /* This notification is received if the application's main - thread exits and the application has other threads running - and the application has open handles for this device. What - we do is to unblock them all simialr to an explicit unblock - call. */ - log_debug ("GPG_IOControl (ctx=%i): code: NOTIFY\n", opnctx_arg); - - if (unblock_call (opnctx)) - result = TRUE; - break; - - default: - log_debug ("GPG_IOControl (ctx=%i): code: (unknown)\n", opnctx_arg); - SetLastError (ERROR_INVALID_PARAMETER); - break; - } - - log_debug ("GPG_IOControl (ctx=%i): success: result=%d\n", opnctx_arg, - result); - - leave: - LeaveCriticalSection (&opnctx_table_cs); - return result; -} - - - -void -GPG_PowerUp (DWORD devctx) -{ - log_debug ("GPG_PowerUp (devctx=%i)\n", devctx); -} - - - -void -GPG_PowerDown (DWORD devctx) -{ - log_debug ("GPG_PowerDown (devctx=%i)\n", devctx); -} - - - - - -/* Entry point called by the DLL loader. */ -int WINAPI -DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved) -{ - (void)reserved; - - switch (reason) - { - case DLL_PROCESS_ATTACH: - InitializeCriticalSection (&opnctx_table_cs); - InitializeCriticalSection (&logcontrol.lock); - break; - - case DLL_THREAD_ATTACH: - break; - - case DLL_THREAD_DETACH: - break; - - case DLL_PROCESS_DETACH: - DeleteCriticalSection (&opnctx_table_cs); - break; - - default: - break; - } - - return TRUE; -} |