spiceqxl_smartcard.c revision d514b0f3
1d514b0f3Smrg/* 2d514b0f3Smrg * Copyright 2014 Jeremy White for CodeWeavers Inc. 3d514b0f3Smrg * 4d514b0f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5d514b0f3Smrg * copy of this software and associated documentation files (the "Software"), 6d514b0f3Smrg * to deal in the Software without restriction, including without limitation 7d514b0f3Smrg * on the rights to use, copy, modify, merge, publish, distribute, sub 8d514b0f3Smrg * license, and/or sell copies of the Software, and to permit persons to whom 9d514b0f3Smrg * the Software is furnished to do so, subject to the following conditions: 10d514b0f3Smrg * 11d514b0f3Smrg * The above copyright notice and this permission notice (including the next 12d514b0f3Smrg * paragraph) shall be included in all copies or substantial portions of the 13d514b0f3Smrg * Software. 14d514b0f3Smrg * 15d514b0f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16d514b0f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17d514b0f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 18d514b0f3Smrg * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19d514b0f3Smrg * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20d514b0f3Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21d514b0f3Smrg */ 22d514b0f3Smrg 23d514b0f3Smrg#ifdef HAVE_CONFIG_H 24d514b0f3Smrg#include "config.h" 25d514b0f3Smrg#endif 26d514b0f3Smrg 27d514b0f3Smrg#include <errno.h> 28d514b0f3Smrg#include <sys/types.h> 29d514b0f3Smrg#include <sys/stat.h> 30d514b0f3Smrg#include <fcntl.h> 31d514b0f3Smrg#include <unistd.h> 32d514b0f3Smrg#include <sys/socket.h> 33d514b0f3Smrg#include <sys/un.h> 34d514b0f3Smrg 35d514b0f3Smrg 36d514b0f3Smrg#include "spiceqxl_smartcard.h" 37d514b0f3Smrg 38d514b0f3Smrgtypedef struct XSpiceSmartcardCharDeviceInstance { 39d514b0f3Smrg SpiceCharDeviceInstance base; 40d514b0f3Smrg qxl_screen_t *qxl; 41d514b0f3Smrg int listen_fd; 42d514b0f3Smrg int fd; 43d514b0f3Smrg SpiceWatch *listen_watch; 44d514b0f3Smrg SpiceWatch *watch; 45d514b0f3Smrg} XSpiceSmartcardCharDeviceInstance; 46d514b0f3Smrg 47d514b0f3Smrgstatic XSpiceSmartcardCharDeviceInstance smartcard_sin = { 48d514b0f3Smrg .base = { 49d514b0f3Smrg .subtype = "smartcard" 50d514b0f3Smrg } 51d514b0f3Smrg}; 52d514b0f3Smrg 53d514b0f3Smrgstatic int smartcard_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) 54d514b0f3Smrg{ 55d514b0f3Smrg int written; 56d514b0f3Smrg 57d514b0f3Smrg if (smartcard_sin.fd == -1) 58d514b0f3Smrg return 0; 59d514b0f3Smrg 60d514b0f3Smrg written = write(smartcard_sin.fd, buf, len); 61d514b0f3Smrg if (written != len) 62d514b0f3Smrg ErrorF("%s: ERROR: short write to smartcard socket - TODO buffering\n", __FUNCTION__); 63d514b0f3Smrg 64d514b0f3Smrg return written; 65d514b0f3Smrg} 66d514b0f3Smrg 67d514b0f3Smrgstatic int smartcard_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) 68d514b0f3Smrg{ 69d514b0f3Smrg int rc; 70d514b0f3Smrg 71d514b0f3Smrg if (smartcard_sin.fd == -1) 72d514b0f3Smrg return 0; 73d514b0f3Smrg 74d514b0f3Smrg rc = read(smartcard_sin.fd, buf, len); 75d514b0f3Smrg if (rc <= 0) { 76d514b0f3Smrg if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { 77d514b0f3Smrg return 0; 78d514b0f3Smrg } 79d514b0f3Smrg ErrorF("smartcard socket died: %s\n", strerror(errno)); 80d514b0f3Smrg 81d514b0f3Smrg smartcard_sin.qxl->core->watch_remove(smartcard_sin.watch); 82d514b0f3Smrg close(smartcard_sin.fd); 83d514b0f3Smrg smartcard_sin.fd = -1; 84d514b0f3Smrg smartcard_sin.watch = NULL; 85d514b0f3Smrg } 86d514b0f3Smrg 87d514b0f3Smrg return rc; 88d514b0f3Smrg} 89d514b0f3Smrg 90d514b0f3Smrgstatic void on_read_available(int fd, int event, void *opaque) 91d514b0f3Smrg{ 92d514b0f3Smrg spice_server_char_device_wakeup(&smartcard_sin.base); 93d514b0f3Smrg} 94d514b0f3Smrg 95d514b0f3Smrgstatic void on_accept_available(int fd, int event, void *opaque) 96d514b0f3Smrg{ 97d514b0f3Smrg qxl_screen_t *qxl = (qxl_screen_t *) opaque; 98d514b0f3Smrg int flags; 99d514b0f3Smrg int client_fd; 100d514b0f3Smrg 101d514b0f3Smrg client_fd = accept(fd, NULL, NULL); 102d514b0f3Smrg if (client_fd < 0) 103d514b0f3Smrg return; 104d514b0f3Smrg 105d514b0f3Smrg if (smartcard_sin.fd != -1) { 106d514b0f3Smrg ErrorF("smartcard error: a new connection came in while an old one was active.\n"); 107d514b0f3Smrg close(client_fd); 108d514b0f3Smrg return; 109d514b0f3Smrg } 110d514b0f3Smrg 111d514b0f3Smrg flags = fcntl(client_fd, F_GETFL, 0); 112d514b0f3Smrg if (flags < 0) 113d514b0f3Smrg flags = 0; 114d514b0f3Smrg flags |= O_NONBLOCK; 115d514b0f3Smrg fcntl(client_fd, F_SETFL, flags); 116d514b0f3Smrg 117d514b0f3Smrg smartcard_sin.fd = client_fd; 118d514b0f3Smrg smartcard_sin.watch = qxl->core->watch_add(smartcard_sin.fd, SPICE_WATCH_EVENT_READ, on_read_available, qxl); 119d514b0f3Smrg 120d514b0f3Smrg} 121d514b0f3Smrg 122d514b0f3Smrg 123d514b0f3Smrg#if SPICE_SERVER_VERSION >= 0x000c02 124d514b0f3Smrgstatic void smartcard_event(SpiceCharDeviceInstance *sin, uint8_t event) 125d514b0f3Smrg{ 126d514b0f3Smrg ErrorF("%s: unimplemented; event is %d\n", __FUNCTION__, event); 127d514b0f3Smrg} 128d514b0f3Smrg#endif 129d514b0f3Smrg 130d514b0f3Smrgstatic void smartcard_state(SpiceCharDeviceInstance *sin, int connected) 131d514b0f3Smrg{ 132d514b0f3Smrg ErrorF("%s: unimplemented; connected is %d\n", __FUNCTION__, connected); 133d514b0f3Smrg} 134d514b0f3Smrg 135d514b0f3Smrgstatic SpiceCharDeviceInterface smartcard_interface = { 136d514b0f3Smrg .base.type = SPICE_INTERFACE_CHAR_DEVICE, 137d514b0f3Smrg .base.description = "Xspice virtual channel char device", 138d514b0f3Smrg .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR, 139d514b0f3Smrg .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR, 140d514b0f3Smrg .state = smartcard_state, 141d514b0f3Smrg .write = smartcard_write, 142d514b0f3Smrg .read = smartcard_read, 143d514b0f3Smrg#if SPICE_SERVER_VERSION >= 0x000c02 144d514b0f3Smrg .event = smartcard_event, 145d514b0f3Smrg#endif 146d514b0f3Smrg}; 147d514b0f3Smrg 148d514b0f3Smrgint 149d514b0f3Smrgqxl_add_spice_smartcard_interface (qxl_screen_t *qxl) 150d514b0f3Smrg{ 151d514b0f3Smrg int rc; 152d514b0f3Smrg struct sockaddr_un addr; 153d514b0f3Smrg 154d514b0f3Smrg if (qxl->smartcard_file[0] == 0) { 155d514b0f3Smrg xf86DrvMsg(qxl->pScrn->scrnIndex, X_INFO, "smartcard: no file given, smartcard is disabled\n"); 156d514b0f3Smrg return 0; 157d514b0f3Smrg } 158d514b0f3Smrg 159d514b0f3Smrg smartcard_sin.fd = -1; 160d514b0f3Smrg smartcard_sin.listen_fd = socket(AF_UNIX, SOCK_STREAM, 0); 161d514b0f3Smrg if (smartcard_sin.listen_fd < 0) { 162d514b0f3Smrg ErrorF("smartcard: unable to open socket: %s\n", strerror(errno)); 163d514b0f3Smrg return errno; 164d514b0f3Smrg } 165d514b0f3Smrg 166d514b0f3Smrg memset(&addr, 0, sizeof(addr)); 167d514b0f3Smrg addr.sun_family = AF_UNIX; 168d514b0f3Smrg strncpy(addr.sun_path, qxl->smartcard_file, sizeof(addr.sun_path) - 1); 169d514b0f3Smrg unlink(qxl->smartcard_file); 170d514b0f3Smrg 171d514b0f3Smrg if (bind(smartcard_sin.listen_fd, (struct sockaddr *) &addr, sizeof(addr))) { 172d514b0f3Smrg ErrorF("smartcard: unable to bind to unix domain %s: %s\n", qxl->smartcard_file, strerror(errno)); 173d514b0f3Smrg close(smartcard_sin.listen_fd); 174d514b0f3Smrg return errno; 175d514b0f3Smrg } 176d514b0f3Smrg 177d514b0f3Smrg if (listen(smartcard_sin.listen_fd, 1)) { 178d514b0f3Smrg ErrorF("smartcard: unable to listen to unix domain %s: %s\n", qxl->smartcard_file, strerror(errno)); 179d514b0f3Smrg close(smartcard_sin.listen_fd); 180d514b0f3Smrg return errno; 181d514b0f3Smrg } 182d514b0f3Smrg 183d514b0f3Smrg smartcard_sin.listen_watch = qxl->core->watch_add(smartcard_sin.listen_fd, SPICE_WATCH_EVENT_READ, on_accept_available, qxl); 184d514b0f3Smrg 185d514b0f3Smrg smartcard_sin.base.base.sif = &smartcard_interface.base; 186d514b0f3Smrg smartcard_sin.qxl = qxl; 187d514b0f3Smrg 188d514b0f3Smrg rc = spice_server_add_interface(qxl->spice_server, &smartcard_sin.base.base); 189d514b0f3Smrg if (rc < 0) 190d514b0f3Smrg return errno; 191d514b0f3Smrg 192d514b0f3Smrg return 0; 193d514b0f3Smrg} 194