pcsc-lite  1.8.25
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 <stdio.h>
55 #include <time.h>
56 #include <string.h>
57 #include <stdlib.h>
58 #ifdef HAVE_SYS_FILIO_H
59 #include <sys/filio.h>
60 #endif
61 
62 #include "misc.h"
63 #include "pcscd.h"
64 #include "winscard.h"
65 #include "debuglog.h"
66 #include "winscard_msg.h"
67 #include "sys_generic.h"
68 #include "utils.h"
69 
70 #ifdef PCSCD
71 
72 /* functions used by pcscd only */
73 
74 #else
75 
76 /* functions used by libpcsclite only */
77 
78 #ifndef SOCK_CLOEXEC
79 #define SOCK_CLOEXEC 0
80 #endif
81 
82 #define member_size(type, member) sizeof(((type *)0)->member)
83 
84 char *getSocketName(void)
85 {
86  static char socketName[member_size(struct sockaddr_un, sun_path)];
87 
88  if ('\0' == socketName[0])
89  {
90  /* socket name not yet initialized */
91  char *socketNameEnv;
92 
93  socketNameEnv = getenv("PCSCLITE_CSOCK_NAME");
94  if (socketNameEnv)
95  strncpy(socketName, socketNameEnv, sizeof(socketName));
96  else
97  strncpy(socketName, PCSCLITE_CSOCK_NAME, sizeof(socketName));
98 
99  /* Ensure a NUL byte */
100  socketName[sizeof socketName -1] = '\0';
101  }
102 
103  return socketName;
104 }
105 
119 INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
120 {
121  struct sockaddr_un svc_addr;
122  int ret;
123  char *socketName;
124 
125  ret = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
126  if (ret < 0)
127  {
128  Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
129  strerror(errno));
130  return -1;
131  }
132  *pdwClientID = ret;
133 
134  socketName = getSocketName();
135  svc_addr.sun_family = AF_UNIX;
136  strncpy(svc_addr.sun_path, socketName, sizeof(svc_addr.sun_path));
137 
138  if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
139  sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
140  {
141  Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s",
142  socketName, strerror(errno));
143  (void)close(*pdwClientID);
144  return -1;
145  }
146 
147  ret = fcntl(*pdwClientID, F_GETFL, 0);
148  if (ret < 0)
149  {
150  Log3(PCSC_LOG_CRITICAL, "Error: cannot retrieve socket %s flags: %s",
151  socketName, strerror(errno));
152  (void)close(*pdwClientID);
153  return -1;
154  }
155 
156  if (fcntl(*pdwClientID, F_SETFL, ret | O_NONBLOCK) < 0)
157  {
158  Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s",
159  socketName, strerror(errno));
160  (void)close(*pdwClientID);
161  return -1;
162  }
163 
164  return 0;
165 }
166 
174 INTERNAL void ClientCloseSession(uint32_t dwClientID)
175 {
176  close(dwClientID);
177 }
178 
195 INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void,
196  uint64_t buffer_size, int32_t filedes, long timeOut)
197 {
198  char *buffer = buffer_void;
199 
200  /* default is success */
201  LONG retval = SCARD_S_SUCCESS;
202 
203  /* record the time when we started */
204  struct timeval start;
205 
206  /* how many bytes we must read */
207  size_t remaining = buffer_size;
208 
209  gettimeofday(&start, NULL);
210 
211  /* repeat until we get the whole message */
212  while (remaining > 0)
213  {
214  fd_set read_fd;
215  struct timeval timeout, now;
216  int selret;
217  long delta;
218 
219  gettimeofday(&now, NULL);
220  delta = time_sub(&now, &start);
221 
222  if (delta > timeOut*1000)
223  {
224  /* we already timed out */
225  retval = SCARD_E_TIMEOUT;
226  break;
227  }
228 
229  /* remaining time to wait */
230  delta = timeOut*1000 - delta;
231 
232  FD_ZERO(&read_fd);
233  FD_SET(filedes, &read_fd);
234 
235  timeout.tv_sec = delta/1000000;
236  timeout.tv_usec = delta - timeout.tv_sec*1000000;
237 
238  selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout);
239 
240  /* try to read only when socket is readable */
241  if (selret > 0)
242  {
243  int readed;
244 
245  if (!FD_ISSET(filedes, &read_fd))
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 (selret == 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 
356 INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
357  int32_t filedes)
358 {
359  char *buffer = buffer_void;
360 
361  /* default is success */
362  LONG retval = SCARD_S_SUCCESS;
363 
364  /* how many bytes remains to be written */
365  size_t remaining = buffer_size;
366 
367  /* repeat until all data is written */
368  while (remaining > 0)
369  {
370  fd_set write_fd;
371  int selret;
372 
373  FD_ZERO(&write_fd);
374  FD_SET(filedes, &write_fd);
375 
376  selret = select(filedes + 1, NULL, &write_fd, NULL, NULL);
377 
378  /* try to write only when the file descriptor is writable */
379  if (selret > 0)
380  {
381  int written;
382 
383  if (!FD_ISSET(filedes, &write_fd))
384  {
385  /* very strange situation. it should be an assert really */
386  retval = SCARD_F_COMM_ERROR;
387  break;
388  }
389  /* since we are a user library we can't play with signals
390  * The signals may already be used by the application */
391 #ifdef MSG_NOSIGNAL
392  /* Get EPIPE return code instead of SIGPIPE signal
393  * Works on Linux */
394  written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
395 #else
396  /* we may get a SIGPIPE signal if the other side has closed */
397  written = write(filedes, buffer, remaining);
398 #endif
399 
400  if (written > 0)
401  {
402  /* we wrote something */
403  buffer += written;
404  remaining -= written;
405  } else if (written == 0)
406  {
407  /* peer closed the socket */
408  retval = SCARD_F_COMM_ERROR;
409  break;
410  } else
411  {
412  /* we ignore the signals and socket full situations, all
413  * other errors are fatal */
414  if (errno != EINTR && errno != EAGAIN)
415  {
416  retval = SCARD_E_NO_SERVICE;
417  break;
418  }
419  }
420  } else if (selret == 0)
421  {
422  /* timeout */
423  retval = SCARD_E_TIMEOUT;
424  break;
425  } else
426  {
427  /* ignore signals */
428  if (errno != EINTR)
429  {
430  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
431  strerror(errno));
432  retval = SCARD_F_COMM_ERROR;
433  break;
434  }
435  }
436  }
437 
438  return retval;
439 }
440 
454 INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
455  int32_t filedes)
456 {
457  char *buffer = buffer_void;
458 
459  /* default is success */
460  LONG retval = SCARD_S_SUCCESS;
461 
462  /* how many bytes we must read */
463  size_t remaining = buffer_size;
464 
465  /* repeat until we get the whole message */
466  while (remaining > 0)
467  {
468  fd_set read_fd;
469  int selret;
470 
471  FD_ZERO(&read_fd);
472  FD_SET(filedes, &read_fd);
473 
474  selret = select(filedes + 1, &read_fd, NULL, NULL, NULL);
475 
476  /* try to read only when socket is readable */
477  if (selret > 0)
478  {
479  int readed;
480 
481  if (!FD_ISSET(filedes, &read_fd))
482  {
483  /* very strange situation. it should be an assert really */
484  retval = SCARD_F_COMM_ERROR;
485  break;
486  }
487  readed = read(filedes, buffer, remaining);
488 
489  if (readed > 0)
490  {
491  /* we got something */
492  buffer += readed;
493  remaining -= readed;
494  } else if (readed == 0)
495  {
496  /* peer closed the socket */
497  retval = SCARD_F_COMM_ERROR;
498  break;
499  } else
500  {
501  /* we ignore the signals and empty socket situations, all
502  * other errors are fatal */
503  if (errno != EINTR && errno != EAGAIN)
504  {
505  retval = SCARD_F_COMM_ERROR;
506  break;
507  }
508  }
509  }
510  else
511  {
512  /* we ignore signals, all other errors are fatal */
513  if (errno != EINTR)
514  {
515  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
516  strerror(errno));
517  retval = SCARD_F_COMM_ERROR;
518  break;
519  }
520  }
521  }
522 
523  return retval;
524 }
525 
#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:174
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
uint32_t command
one of the pcsc_msg_commands
Definition: winscard_msg.h:67
This handles abstract system level calls.
header structure for client/server message data exchange.
Definition: winscard_msg.h:64
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:454
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:136
#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:66
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:119
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:356
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 reponse from the server or vice-versa.
Definition: winscard_msg.c:195
This handles debugging.