📄 scard.c
字号:
/* rdesktop: A Remote Desktop Protocol client. Smart Card support Copyright (C) Alexi Volkov <alexi@myrealbox.com> 2006 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <strings.h>#include <sys/types.h>#include <time.h>#ifndef MAKE_PROTO#ifdef __APPLE__#include <PCSC/wintypes.h>#include <PCSC/pcsclite.h>#include <PCSC/winscard.h>#else#include <wintypes.h>#include <pcsclite.h>#include <winscard.h>#endif /* PCSC_OSX */#include "rdesktop.h"#include "scard.h"/* variable segment */#define SCARD_MAX_MEM 102400#define SCARD_AUTOALLOCATE -1#define OUT_STREAM_SIZE 4096#ifdef B_ENDIAN#define swap32(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | \ (((x) & 0xff0000) >> 8) | (((x) & 0xff000000) >> 24))#define swap16(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))#else#define swap32(x) (x)#define swap16(x) (x)#endifstatic pthread_mutex_t **scard_mutex = NULL;static uint32 curDevice = 0, curId = 0, curBytesOut = 0;static PSCNameMapRec nameMapList = NULL;static int nameMapCount = 0;static pthread_t queueHandler;static pthread_mutex_t queueAccess;static pthread_cond_t queueEmpty;static pthread_mutex_t hcardAccess;static PMEM_HANDLE threadListHandle = NULL;static PThreadListElement threadList = NULL;static PSCThreadData queueFirst = NULL, queueLast = NULL;static int threadCount = 0;static PSCHCardRec hcardFirst = NULL;static void *queue_handler_function(void *data);/* code segment */#endif /* MAKE_PROTO */voidscardSetInfo(uint32 device, uint32 id, uint32 bytes_out){ curDevice = device; curId = id; curBytesOut = bytes_out;}#ifndef MAKE_PROTOstatic RD_NTSTATUSscard_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create_disposition, uint32 flags_and_attributes, char *filename, RD_NTHANDLE * phandle){ return RD_STATUS_SUCCESS;}static RD_NTSTATUSscard_close(RD_NTHANDLE handle){ return RD_STATUS_SUCCESS;}static RD_NTSTATUSscard_read(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result){ return RD_STATUS_SUCCESS;}static RD_NTSTATUSscard_write(RD_NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result){ return RD_STATUS_SUCCESS;}#endif /* MAKE_PROTO *//* Enumeration of devices from rdesktop.c *//* returns numer of units found and initialized. *//* optarg looks like ':"ReaderName=ReaderAlias"' *//* when it arrives to this function. */intscard_enum_devices(uint32 * id, char *optarg){ char *name = optarg + 1; char *alias; int count = 0; PSCNameMapRec tmpMap; MYPCSC_DWORD rv; SCARDCONTEXT hContext; /* code segment */ rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); if (rv != SCARD_S_SUCCESS) { error("scard_enum_devices: PCSC service not available\n"); return 0; } else rv = SCardReleaseContext(hContext); count = 0; if (0 != pthread_mutex_init(&queueAccess, NULL)) { error("scard_enum_devices: Can't initialize queue access mutex\n"); return 0; } if (0 != pthread_cond_init(&queueEmpty, NULL)) { error("scard_enum_devices: Can't initialize queue control cv\n"); return 0; } if (0 != pthread_mutex_init(&hcardAccess, NULL)) { error("scard_enum_devices: Can't initialize hcard list access mutex\n"); return 0; } if (0 != pthread_create(&queueHandler, NULL, (void *(*)(void *)) queue_handler_function, NULL)) { error("scard_enum_devices: Can't create queue handling Thread\n"); return 0; } strncpy(g_rdpdr_device[*id].name, "SCARD\0\0\0", 8); toupper_str(g_rdpdr_device[*id].name); g_rdpdr_device[*id].local_path = "/dev/scard"; g_rdpdr_device[*id].pdevice_data = NULL; g_rdpdr_device[*id].handle = 0; g_rdpdr_device[*id].device_type = DEVICE_TYPE_SCARD; count++; (*id)++; if (*optarg == ':') { while ((optarg = next_arg(name, ',')) && *id < RDPDR_MAX_DEVICES) { int len; char *vendor = NULL; alias = next_arg(name, '='); vendor = next_arg(alias, ';'); if (strlen(name) > 0) { if (!strlen(alias)) { alias = name; vendor = "\0"; } printf("Static/aliased Device:\n"); printf(" Lin name: [%s]\n", name); printf(" Win name: [%s]\n", alias); printf(" Vendor : [%s]\n", vendor); nameMapCount++; if (nameMapList == NULL) nameMapList = xmalloc(nameMapCount * sizeof(TSCNameMapRec)); else nameMapList = xrealloc(nameMapList, nameMapCount * sizeof(TSCNameMapRec)); tmpMap = nameMapList + nameMapCount - 1; len = strlen(alias); strncpy(tmpMap->alias, alias, (len > 127) ? (127) : (len)); len = strlen(name); strncpy(tmpMap->name, name, (len > 127) ? (127) : (len)); if (vendor) { len = strlen(vendor); if (len > 0) { memset(tmpMap->vendor, 0, 128); strncpy(tmpMap->vendor, vendor, (len > 127) ? (127) : (len)); } else tmpMap->vendor[0] = '\0'; } else tmpMap->vendor[0] = '\0'; } name = optarg; } } return count;}#ifndef MAKE_PROTO/* ---------------------------------- *//* These two functions depend heavily on the actual implementation of the smart * card handle in PC/SC Lite 1.3.1. Here are the salient bits: * * From winscard.c:331, in SCardConnect: * *phCard = RFCreateReaderHandle(rContext); * * RFCreateReaderHandle (readerfactory.c:1161) creates a random short (16-bit * integer) and makes sure it's unique. Then it adds it to * rContext->dwIdentity. * * From readerfactory.c:173, in RFAddReader: * (sReadersContexts[dwContext])->dwIdentity = * (dwContext + 1) << (sizeof(DWORD) / 2) * 8; * * dwContext must be less than PCSCLITE_MAX_READERS_CONTEXTS, which is defined * to be 16 in the 1.3.1 release. * * The use of "(sizeof(DWORD) / 2) * 8" is what makes conversion necessary in * order to use 64-bit card handles when talking to PC/SC Lite, and 32-bit card * handles when talking with the server, without losing any data: a card handle * made by a 32-bit PC/SC Lite looks like 0x00014d32, where the 4d32 is the * random 16 bits, 01 is the reader context index + 1, and it's left-shifted by * 16 bits (sizeof(DWORD) == 4, divided by 2 is 2, times 8 is 16.) But a 64-bit * PC/SC Lite makes a card handle that looks like 0x0000000100004d32. The * reader context index+1 is left-shifted 32 bits because sizeof(DWORD) is 8, * not 4. This means the handle won't fit in 32 bits. (The multiplication by 8 * is because sizeofs are in bytes, but saying how many places to left-shift is * speaking in bits.) * * So then. Maximum value of dwContext+1 is 17; we'll say this fits in a byte * to be loose and have plenty of room. This is then left-shifted by * sizeof(DWORD) / 2 * 8 - which in this file is sizeof(MYPCSC_DWORD) / 2 * 8. * * At any rate, if we take the handle as passed from PC/SC Lite, right-shift by * sizeof(MYPCSC_DWORD) / 2, left-shift by sizeof(SERVER_DWORD) / 2, and add * the lower two bytes of the value (the random number), we can fit all the * information into 32 bits without losing any. Of course, any time we want to * hand that back to PC/SC Lite, we'll have to expand it again. (And if * sizeof(MYPCSC_DWORD) == sizeof(SERVER_DWORD), we're essentially doing * nothing, which will not break anything.) * * * - jared.jennings@eglin.af.mil, 2 Aug 2006 */static MYPCSC_SCARDHANDLEscHandleToMyPCSC(SERVER_SCARDHANDLE server){ return (((MYPCSC_SCARDHANDLE) server >> (sizeof(SERVER_DWORD) * 8 / 2) & 0xffff) << (sizeof(MYPCSC_DWORD) * 8 / 2)) + (server & 0xffff);}static SERVER_SCARDHANDLEscHandleToServer(MYPCSC_SCARDHANDLE mypcsc){ return ((mypcsc >> (sizeof(MYPCSC_DWORD) * 8 / 2) & 0xffff) << (sizeof(SERVER_DWORD) * 8 / 2)) + (mypcsc & 0xffff);}/* ---------------------------------- */static void *SC_xmalloc(PMEM_HANDLE * memHandle, unsigned int size){ PMEM_HANDLE handle = NULL; if (size > 0 && memHandle) { handle = xmalloc(size + sizeof(MEM_HANDLE)); if (handle) { handle->prevHandle = NULL; handle->nextHandle = NULL; handle->dataSize = size; if (*memHandle) { handle->prevHandle = *memHandle; (*memHandle)->nextHandle = handle; } *memHandle = handle; return handle + 1; } else return NULL; } else return NULL;}static voidSC_xfree(PMEM_HANDLE * handle, void *memptr){ if (memptr != NULL) { PMEM_HANDLE lcHandle = (PMEM_HANDLE) memptr - 1; if (lcHandle->dataSize > 0) { memset(memptr, 0, lcHandle->dataSize); if (lcHandle->nextHandle) lcHandle->nextHandle->prevHandle = lcHandle->prevHandle; if (lcHandle->prevHandle) lcHandle->prevHandle->nextHandle = lcHandle->nextHandle; if (*handle == lcHandle) { if (lcHandle->prevHandle) *handle = lcHandle->prevHandle; else *handle = lcHandle->nextHandle; } xfree(lcHandle); } }}static voidSC_xfreeallmemory(PMEM_HANDLE * handle){ if (handle && (*handle)) { if ((*handle)->prevHandle) { (*handle)->prevHandle->nextHandle = NULL; SC_xfreeallmemory(&((*handle)->prevHandle)); } if ((*handle)->nextHandle) { (*handle)->nextHandle->prevHandle = NULL; SC_xfreeallmemory(&((*handle)->nextHandle)); } memset(*handle, 0, (*handle)->dataSize + sizeof(MEM_HANDLE)); xfree(*handle); *handle = NULL; }}/* ---------------------------------- */static char *getName(char *alias){ int i; PSCNameMapRec tmpMap; for (i = 0, tmpMap = nameMapList; i < nameMapCount; i++, tmpMap++) { if (strcmp(tmpMap->alias, alias) == 0) return tmpMap->name; } return alias;}static char *getVendor(char *name){ int i; PSCNameMapRec tmpMap; for (i = 0, tmpMap = nameMapList; i < nameMapCount; i++, tmpMap++) { if (strcmp(tmpMap->name, name) == 0) return tmpMap->vendor; } return NULL;}static char *getAlias(char *name){ int i; PSCNameMapRec tmpMap; for (i = 0, tmpMap = nameMapList; i < nameMapCount; i++, tmpMap++) { if (strcmp(tmpMap->name, name) == 0) return tmpMap->alias; } return name;}static inthasAlias(char *name){ int i; PSCNameMapRec tmpMap; for (i = 0, tmpMap = nameMapList; i < nameMapCount; i++, tmpMap++) { if (strcmp(tmpMap->name, name) == 0) return 1; } return 0;}static voidinRepos(STREAM in, unsigned int read){ SERVER_DWORD add = 4 - read % 4; if (add < 4 && add > 0) { in_uint8s(in, add); }}static voidoutRepos(STREAM out, unsigned int written){ SERVER_DWORD add = (4 - written % 4) % 4; if (add > 0) { out_uint8s(out, add); }}static voidoutBufferStartWithLimit(STREAM out, int length, int highLimit){ int header = (length < 0) ? (0) : ((length > highLimit) ? (highLimit) : (length)); out_uint32_le(out, header); out_uint32_le(out, 0x00000001); /* Magic DWORD - any non zero */}static voidoutBufferStart(STREAM out, int length){ outBufferStartWithLimit(out, length, 0x7FFFFFFF);}static voidoutBufferFinishWithLimit(STREAM out, char *buffer, unsigned int length, unsigned int highLimit){ int header = (length < 0) ? (0) : ((length > highLimit) ? (highLimit) : (length)); out_uint32_le(out, header); if (length <= 0) { out_uint32_le(out, 0x00000000); } else { if (header < length) length = header; out_uint8p(out, buffer, length); outRepos(out, length); }}static voidoutBufferFinish(STREAM out, char *buffer, unsigned int length){ outBufferFinishWithLimit(out, buffer, length, 0x7FFFFFFF);}static voidoutForceAlignment(STREAM out, unsigned int seed){ SERVER_DWORD add = (seed - (out->p - out->data) % seed) % seed; if (add > 0) out_uint8s(out, add);}static unsigned int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -