pcsc-lite  2.0.3
winscard_msg.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 2001-2004
5  * David Corcoran <corcoran@musclecard.com>
6  * Copyright (C) 2003-2004
7  * Damien Sauveron <damien.sauveron@labri.fr>
8  * Copyright (C) 2002-2010
9  * Ludovic Rousseau <ludovic.rousseau@free.fr>
10  *
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions
13 are met:
14 
15 1. Redistributions of source code must retain the above copyright
16  notice, this list of conditions and the following disclaimer.
17 2. Redistributions in binary form must reproduce the above copyright
18  notice, this list of conditions and the following disclaimer in the
19  documentation and/or other materials provided with the distribution.
20 3. The name of the author may not be used to endorse or promote products
21  derived from this software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
44 #include "config.h"
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <sys/socket.h>
50 #include <sys/time.h>
51 #include <sys/un.h>
52 #include <sys/ioctl.h>
53 #include <errno.h>
54 #include <poll.h>
55 #include <stdio.h>
56 #include <time.h>
57 #include <string.h>
58 #include <stdlib.h>
59 #ifdef HAVE_SYS_FILIO_H
60 #include <sys/filio.h>
61 #endif
62 
63 #include "misc.h"
64 #include "pcscd.h"
65 #include "winscard.h"
66 #include "debuglog.h"
67 #include "winscard_msg.h"
68 #include "sys_generic.h"
69 #include "utils.h"
70 
71 #ifdef PCSCD
72 
73 /* functions used by pcscd only */
74 
75 #else
76 
77 /* functions used by libpcsclite only */
78 
79 #ifndef SOCK_CLOEXEC
80 #define SOCK_CLOEXEC 0
81 #endif
82 
83 #define member_size(type, member) sizeof(((type *)0)->member)
84 
85 static char SocketName[member_size(struct sockaddr_un, sun_path)];
86 static pthread_once_t SocketName_init_control = PTHREAD_ONCE_INIT;
87 static void SocketName_init(void)
88 {
89  /* socket name not yet initialized */
90  char *socketNameEnv;
91 
92  socketNameEnv = getenv("PCSCLITE_CSOCK_NAME");
93  if (socketNameEnv)
94  strncpy(SocketName, socketNameEnv, sizeof SocketName);
95  else
96  strncpy(SocketName, PCSCLITE_CSOCK_NAME, sizeof SocketName);
97 
98  /* Ensure a NUL byte */
99  SocketName[sizeof SocketName -1] = '\0';
100 }
101 
102 char *getSocketName(void)
103 {
104  pthread_once(&SocketName_init_control, SocketName_init);
105  return SocketName;
106 }
107 
122 INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
123 {
124  struct sockaddr_un svc_addr;
125  int ret;
126  char *socketName;
127 
128  ret = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
129  if (ret < 0)
130  {
131  Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
132  strerror(errno));
133  return -1;
134  }
135  *pdwClientID = ret;
136 
137  socketName = getSocketName();
138  svc_addr.sun_family = AF_UNIX;
139  strncpy(svc_addr.sun_path, socketName, sizeof(svc_addr.sun_path));
140 
141  if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
142  sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
143  {
144  Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s",
145  socketName, strerror(errno));
146  (void)close(*pdwClientID);
147  return -1;
148  }
149 
150  ret = fcntl(*pdwClientID, F_GETFL, 0);
151  if (ret < 0)
152  {
153  Log3(PCSC_LOG_CRITICAL, "Error: cannot retrieve socket %s flags: %s",
154  socketName, strerror(errno));
155  (void)close(*pdwClientID);
156  return -1;
157  }
158 
159  if (fcntl(*pdwClientID, F_SETFL, ret | O_NONBLOCK) < 0)
160  {
161  Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s",
162  socketName, strerror(errno));
163  (void)close(*pdwClientID);
164  return -1;
165  }
166 
167  return 0;
168 }
169 
176 INTERNAL void ClientCloseSession(uint32_t dwClientID)
177 {
178  close(dwClientID);
179 }
180 
198 INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void,
199  uint64_t buffer_size, int32_t filedes, long timeOut)
200 {
201  char *buffer = buffer_void;
202 
203  /* default is success */
204  LONG retval = SCARD_S_SUCCESS;
205 
206  /* record the time when we started */
207  struct timeval start;
208 
209  /* how many bytes we must read */
210  size_t remaining = buffer_size;
211 
212  gettimeofday(&start, NULL);
213 
214  /* repeat until we get the whole message */
215  while (remaining > 0)
216  {
217  struct pollfd read_fd;
218  struct timeval now;
219  int pollret;
220  long delta;
221 
222  gettimeofday(&now, NULL);
223  delta = time_sub(&now, &start) / 1000;
224 
225  if (delta > timeOut)
226  {
227  /* we already timed out */
228  retval = SCARD_E_TIMEOUT;
229  break;
230  }
231 
232  /* remaining time to wait */
233  delta = timeOut - delta;
234 
235  read_fd.fd = filedes;
236  read_fd.events = POLLIN;
237  read_fd.revents = 0;
238 
239  pollret = poll(&read_fd, 1, delta);
240 
241  /* try to read only when socket is readable */
242  if (pollret > 0)
243  {
244  int bytes_read;
245 
246  if (!(read_fd.revents & POLLIN))
247  {
248  /* very strange situation. it should be an assert really */
249  retval = SCARD_F_COMM_ERROR;
250  break;
251  }
252  bytes_read = read(filedes, buffer, remaining);
253 
254  if (bytes_read > 0)
255  {
256  /* we got something */
257  buffer += bytes_read;
258  remaining -= bytes_read;
259  } else if (bytes_read == 0)
260  {
261  /* peer closed the socket */
262  retval = SCARD_F_COMM_ERROR;
263  break;
264  } else
265  {
266  /* we ignore the signals and empty socket situations, all
267  * other errors are fatal */
268  if (errno != EINTR && errno != EAGAIN)
269  {
270  retval = SCARD_F_COMM_ERROR;
271  break;
272  }
273  }
274  } else if (pollret == 0)
275  {
276  /* is the daemon still there? */
277  retval = SCardCheckDaemonAvailability();
278  if (retval != SCARD_S_SUCCESS)
279  {
280  /* timeout */
281  break;
282  }
283 
284  /* you need to set the env variable PCSCLITE_DEBUG=0 since
285  * this is logged on the client side and not on the pcscd
286  * side*/
287 #ifdef NO_LOG
288  (void)command;
289 #endif
290  Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command);
291  } else
292  {
293  /* we ignore signals, all other errors are fatal */
294  if (errno != EINTR)
295  {
296  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
297  strerror(errno));
298  retval = SCARD_F_COMM_ERROR;
299  break;
300  }
301  }
302  }
303 
304  return retval;
305 }
306 
321 INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID,
322  uint64_t size, void *data_void)
323 {
324  struct rxHeader header;
325  LONG ret;
326 
327  /* header */
328  header.command = command;
329  header.size = size;
330  ret = MessageSend(&header, sizeof(header), dwClientID);
331 
332  /* command */
333  if (size > 0)
334  ret = MessageSend(data_void, size, dwClientID);
335 
336  return ret;
337 }
338 
339 #endif
340 
341 /* functions used by pcscd and libpcsclite */
342 
358 INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
359  int32_t filedes)
360 {
361  char *buffer = buffer_void;
362 
363  /* default is success */
364  LONG retval = SCARD_S_SUCCESS;
365 
366  /* how many bytes remains to be written */
367  size_t remaining = buffer_size;
368 
369  /* repeat until all data is written */
370  while (remaining > 0)
371  {
372  struct pollfd write_fd;
373  int pollret;
374 
375  write_fd.fd = filedes;
376  write_fd.events = POLLOUT;
377  write_fd.revents = 0;
378 
379  pollret = poll(&write_fd, 1, -1);
380 
381  /* try to write only when the file descriptor is writable */
382  if (pollret > 0)
383  {
384  int written;
385 
386  if (!(write_fd.revents & POLLOUT))
387  {
388  /* very strange situation. it should be an assert really */
389  retval = SCARD_F_COMM_ERROR;
390  break;
391  }
392  /* since we are a user library we can't play with signals
393  * The signals may already be used by the application */
394 #ifdef MSG_NOSIGNAL
395  /* Get EPIPE return code instead of SIGPIPE signal
396  * Works on Linux */
397  written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
398 #else
399  /* we may get a SIGPIPE signal if the other side has closed */
400  written = write(filedes, buffer, remaining);
401 #endif
402 
403  if (written > 0)
404  {
405  /* we wrote something */
406  buffer += written;
407  remaining -= written;
408  } else if (written == 0)
409  {
410  /* peer closed the socket */
411  retval = SCARD_F_COMM_ERROR;
412  break;
413  } else
414  {
415  /* we ignore the signals and socket full situations, all
416  * other errors are fatal */
417  if (errno != EINTR && errno != EAGAIN)
418  {
419  retval = SCARD_E_NO_SERVICE;
420  break;
421  }
422  }
423  } else if (pollret == 0)
424  {
425  /* timeout */
426  retval = SCARD_E_TIMEOUT;
427  break;
428  } else
429  {
430  /* ignore signals */
431  if (errno != EINTR)
432  {
433  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
434  strerror(errno));
435  retval = SCARD_F_COMM_ERROR;
436  break;
437  }
438  }
439  }
440 
441  return retval;
442 }
443 
458 INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
459  int32_t filedes)
460 {
461  char *buffer = buffer_void;
462 
463  /* default is success */
464  LONG retval = SCARD_S_SUCCESS;
465 
466  /* how many bytes we must read */
467  size_t remaining = buffer_size;
468 
469  /* repeat until we get the whole message */
470  while (remaining > 0)
471  {
472  struct pollfd read_fd;
473  int pollret;
474 
475  read_fd.fd = filedes;
476  read_fd.events = POLLIN;
477  read_fd.revents = 0;
478 
479  pollret = poll(&read_fd, 1 , -1);
480 
481  /* try to read only when socket is readable */
482  if (pollret > 0)
483  {
484  int bytes_read;
485 
486  if (!(read_fd.revents & POLLIN))
487  {
488  /* very strange situation. it should be an assert really */
489  retval = SCARD_F_COMM_ERROR;
490  break;
491  }
492  bytes_read = read(filedes, buffer, remaining);
493 
494  if (bytes_read > 0)
495  {
496  /* we got something */
497  buffer += bytes_read;
498  remaining -= bytes_read;
499  } else if (bytes_read == 0)
500  {
501  /* peer closed the socket */
502  retval = SCARD_F_COMM_ERROR;
503  break;
504  } else
505  {
506  /* we ignore the signals and empty socket situations, all
507  * other errors are fatal */
508  if (errno != EINTR && errno != EAGAIN)
509  {
510  /* connection reset by pcscd? */
511  if (ECONNRESET == errno)
513  else
514  retval = SCARD_F_COMM_ERROR;
515  break;
516  }
517  }
518  }
519  else
520  {
521  /* we ignore signals, all other errors are fatal */
522  if (errno != EINTR)
523  {
524  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
525  strerror(errno));
526  retval = SCARD_F_COMM_ERROR;
527  break;
528  }
529  }
530  }
531 
532  return retval;
533 }
534 
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:127
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:176
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:321
uint32_t command
one of the pcsc_msg_commands
Definition: winscard_msg.h:70
#define SCARD_W_SECURITY_VIOLATION
Access was denied because of a security violation.
Definition: pcsclite.h:222
This handles abstract system level calls.
header structure for client/server message data exchange.
Definition: winscard_msg.h:67
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the response from the server or vice-versa.
Definition: winscard_msg.c:458
This defines some structures and #defines to be used over the transport layer.
long int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in µs between 2 struct timeval r = a - b
Definition: utils.c:138
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:145
uint32_t size
size of the message excluding this header
Definition: winscard_msg.h:69
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
Definition: winscard_msg.c:122
This keeps a list of defines for pcsc-lite.
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
Definition: winscard_msg.c:358
This handles smart card reader communications.
INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, uint64_t buffer_size, int32_t filedes, long timeOut)
Called by the Client to get the response from the server or vice-versa.
Definition: winscard_msg.c:198
This handles debugging.