pcsc-lite  1.9.0
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 char *getSocketName(void)
86 {
87  static char socketName[member_size(struct sockaddr_un, sun_path)];
88 
89  if ('\0' == socketName[0])
90  {
91  /* socket name not yet initialized */
92  char *socketNameEnv;
93 
94  socketNameEnv = getenv("PCSCLITE_CSOCK_NAME");
95  if (socketNameEnv)
96  strncpy(socketName, socketNameEnv, sizeof(socketName));
97  else
98  strncpy(socketName, PCSCLITE_CSOCK_NAME, sizeof(socketName));
99 
100  /* Ensure a NUL byte */
101  socketName[sizeof socketName -1] = '\0';
102  }
103 
104  return socketName;
105 }
106 
121 INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
122 {
123  struct sockaddr_un svc_addr;
124  int ret;
125  char *socketName;
126 
127  ret = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
128  if (ret < 0)
129  {
130  Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
131  strerror(errno));
132  return -1;
133  }
134  *pdwClientID = ret;
135 
136  socketName = getSocketName();
137  svc_addr.sun_family = AF_UNIX;
138  strncpy(svc_addr.sun_path, socketName, sizeof(svc_addr.sun_path));
139 
140  if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
141  sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
142  {
143  Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s",
144  socketName, strerror(errno));
145  (void)close(*pdwClientID);
146  return -1;
147  }
148 
149  ret = fcntl(*pdwClientID, F_GETFL, 0);
150  if (ret < 0)
151  {
152  Log3(PCSC_LOG_CRITICAL, "Error: cannot retrieve socket %s flags: %s",
153  socketName, strerror(errno));
154  (void)close(*pdwClientID);
155  return -1;
156  }
157 
158  if (fcntl(*pdwClientID, F_SETFL, ret | O_NONBLOCK) < 0)
159  {
160  Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s",
161  socketName, strerror(errno));
162  (void)close(*pdwClientID);
163  return -1;
164  }
165 
166  return 0;
167 }
168 
175 INTERNAL void ClientCloseSession(uint32_t dwClientID)
176 {
177  close(dwClientID);
178 }
179 
197 INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void,
198  uint64_t buffer_size, int32_t filedes, long timeOut)
199 {
200  char *buffer = buffer_void;
201 
202  /* default is success */
203  LONG retval = SCARD_S_SUCCESS;
204 
205  /* record the time when we started */
206  struct timeval start;
207 
208  /* how many bytes we must read */
209  size_t remaining = buffer_size;
210 
211  gettimeofday(&start, NULL);
212 
213  /* repeat until we get the whole message */
214  while (remaining > 0)
215  {
216  struct pollfd read_fd;
217  struct timeval now;
218  int pollret;
219  long delta;
220 
221  gettimeofday(&now, NULL);
222  delta = time_sub(&now, &start) / 1000;
223 
224  if (delta > timeOut)
225  {
226  /* we already timed out */
227  retval = SCARD_E_TIMEOUT;
228  break;
229  }
230 
231  /* remaining time to wait */
232  delta = timeOut - delta;
233 
234  read_fd.fd = filedes;
235  read_fd.events = POLLIN;
236  read_fd.revents = 0;
237 
238  pollret = poll(&read_fd, 1, delta);
239 
240  /* try to read only when socket is readable */
241  if (pollret > 0)
242  {
243  int readed;
244 
245  if (!(read_fd.revents & POLLIN))
246  {
247  /* very strange situation. it should be an assert really */
248  retval = SCARD_F_COMM_ERROR;
249  break;
250  }
251  readed = read(filedes, buffer, remaining);
252 
253  if (readed > 0)
254  {
255  /* we got something */
256  buffer += readed;
257  remaining -= readed;
258  } else if (readed == 0)
259  {
260  /* peer closed the socket */
261  retval = SCARD_F_COMM_ERROR;
262  break;
263  } else
264  {
265  /* we ignore the signals and empty socket situations, all
266  * other errors are fatal */
267  if (errno != EINTR && errno != EAGAIN)
268  {
269  retval = SCARD_F_COMM_ERROR;
270  break;
271  }
272  }
273  } else if (pollret == 0)
274  {
275  /* is the daemon still there? */
276  retval = SCardCheckDaemonAvailability();
277  if (retval != SCARD_S_SUCCESS)
278  {
279  /* timeout */
280  break;
281  }
282 
283  /* you need to set the env variable PCSCLITE_DEBUG=0 since
284  * this is logged on the client side and not on the pcscd
285  * side*/
286 #ifdef NO_LOG
287  (void)command;
288 #endif
289  Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command);
290  } else
291  {
292  /* we ignore signals, all other errors are fatal */
293  if (errno != EINTR)
294  {
295  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
296  strerror(errno));
297  retval = SCARD_F_COMM_ERROR;
298  break;
299  }
300  }
301  }
302 
303  return retval;
304 }
305 
320 INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID,
321  uint64_t size, void *data_void)
322 {
323  struct rxHeader header;
324  LONG ret;
325 
326  /* header */
327  header.command = command;
328  header.size = size;
329  ret = MessageSend(&header, sizeof(header), dwClientID);
330 
331  /* command */
332  if (size > 0)
333  ret = MessageSend(data_void, size, dwClientID);
334 
335  return ret;
336 }
337 
338 #endif
339 
340 /* functions used by pcscd and libpcsclite */
341 
357 INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
358  int32_t filedes)
359 {
360  char *buffer = buffer_void;
361 
362  /* default is success */
363  LONG retval = SCARD_S_SUCCESS;
364 
365  /* how many bytes remains to be written */
366  size_t remaining = buffer_size;
367 
368  /* repeat until all data is written */
369  while (remaining > 0)
370  {
371  struct pollfd write_fd;
372  int pollret;
373 
374  write_fd.fd = filedes;
375  write_fd.events = POLLOUT;
376  write_fd.revents = 0;
377 
378  pollret = poll(&write_fd, 1, -1);
379 
380  /* try to write only when the file descriptor is writable */
381  if (pollret > 0)
382  {
383  int written;
384 
385  if (!(write_fd.revents & POLLOUT))
386  {
387  /* very strange situation. it should be an assert really */
388  retval = SCARD_F_COMM_ERROR;
389  break;
390  }
391  /* since we are a user library we can't play with signals
392  * The signals may already be used by the application */
393 #ifdef MSG_NOSIGNAL
394  /* Get EPIPE return code instead of SIGPIPE signal
395  * Works on Linux */
396  written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
397 #else
398  /* we may get a SIGPIPE signal if the other side has closed */
399  written = write(filedes, buffer, remaining);
400 #endif
401 
402  if (written > 0)
403  {
404  /* we wrote something */
405  buffer += written;
406  remaining -= written;
407  } else if (written == 0)
408  {
409  /* peer closed the socket */
410  retval = SCARD_F_COMM_ERROR;
411  break;
412  } else
413  {
414  /* we ignore the signals and socket full situations, all
415  * other errors are fatal */
416  if (errno != EINTR && errno != EAGAIN)
417  {
418  retval = SCARD_E_NO_SERVICE;
419  break;
420  }
421  }
422  } else if (pollret == 0)
423  {
424  /* timeout */
425  retval = SCARD_E_TIMEOUT;
426  break;
427  } else
428  {
429  /* ignore signals */
430  if (errno != EINTR)
431  {
432  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
433  strerror(errno));
434  retval = SCARD_F_COMM_ERROR;
435  break;
436  }
437  }
438  }
439 
440  return retval;
441 }
442 
457 INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
458  int32_t filedes)
459 {
460  char *buffer = buffer_void;
461 
462  /* default is success */
463  LONG retval = SCARD_S_SUCCESS;
464 
465  /* how many bytes we must read */
466  size_t remaining = buffer_size;
467 
468  /* repeat until we get the whole message */
469  while (remaining > 0)
470  {
471  struct pollfd read_fd;
472  int pollret;
473 
474  read_fd.fd = filedes;
475  read_fd.events = POLLIN;
476  read_fd.revents = 0;
477 
478  pollret = poll(&read_fd, 1 , -1);
479 
480  /* try to read only when socket is readable */
481  if (pollret > 0)
482  {
483  int readed;
484 
485  if (!(read_fd.revents & POLLIN))
486  {
487  /* very strange situation. it should be an assert really */
488  retval = SCARD_F_COMM_ERROR;
489  break;
490  }
491  readed = read(filedes, buffer, remaining);
492 
493  if (readed > 0)
494  {
495  /* we got something */
496  buffer += readed;
497  remaining -= readed;
498  } else if (readed == 0)
499  {
500  /* peer closed the socket */
501  retval = SCARD_F_COMM_ERROR;
502  break;
503  } else
504  {
505  /* we ignore the signals and empty socket situations, all
506  * other errors are fatal */
507  if (errno != EINTR && errno != EAGAIN)
508  {
509  retval = SCARD_F_COMM_ERROR;
510  break;
511  }
512  }
513  }
514  else
515  {
516  /* we ignore signals, all other errors are fatal */
517  if (errno != EINTR)
518  {
519  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
520  strerror(errno));
521  retval = SCARD_F_COMM_ERROR;
522  break;
523  }
524  }
525  }
526 
527  return retval;
528 }
529 
This handles debugging.
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:145
#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
This keeps a list of defines for pcsc-lite.
header structure for client/server message data exchange.
Definition: winscard_msg.h:65
uint32_t size
size of the message excluding this header
Definition: winscard_msg.h:66
uint32_t command
one of the pcsc_msg_commands
Definition: winscard_msg.h:67
This handles abstract system level calls.
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:136
This handles smart card reader communications.
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:121
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 reponse from the server or vice-versa.
Definition: winscard_msg.c:197
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:320
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:357
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:175
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the reponse from the server or vice-versa.
Definition: winscard_msg.c:457
This defines some structures and #defines to be used over the transport layer.