pcsc-lite  2.2.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-2024
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 
60 #include "misc.h"
61 #include "pcscd.h"
62 #include "winscard.h"
63 #include "debuglog.h"
64 #include "winscard_msg.h"
65 #include "sys_generic.h"
66 #include "utils.h"
67 
68 #ifdef PCSCD
69 
70 /* functions used by pcscd only */
71 
72 #else
73 
74 /* functions used by libpcsclite only */
75 
76 #ifndef SOCK_CLOEXEC
77 #define SOCK_CLOEXEC 0
78 #endif
79 
80 #define member_size(type, member) sizeof(((type *)0)->member)
81 
82 static char SocketName[member_size(struct sockaddr_un, sun_path)];
83 static pthread_once_t SocketName_init_control = PTHREAD_ONCE_INIT;
84 static void SocketName_init(void)
85 {
86  /* socket name not yet initialized */
87  const char *socketNameEnv;
88 
89  socketNameEnv = SYS_GetEnv("PCSCLITE_CSOCK_NAME");
90  if (socketNameEnv)
91  strncpy(SocketName, socketNameEnv, sizeof SocketName);
92  else
93  strncpy(SocketName, PCSCLITE_CSOCK_NAME, sizeof SocketName);
94 
95  /* Ensure a NUL byte */
96  SocketName[sizeof SocketName -1] = '\0';
97 }
98 
99 char *getSocketName(void)
100 {
101  pthread_once(&SocketName_init_control, SocketName_init);
102  return SocketName;
103 }
104 
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 
173 INTERNAL void ClientCloseSession(uint32_t dwClientID)
174 {
175  close(dwClientID);
176 }
177 
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  struct pollfd read_fd;
215  struct timeval now;
216  int pollret;
217  long delta;
218 
219  gettimeofday(&now, NULL);
220  delta = time_sub(&now, &start) / 1000;
221 
222  if (delta > timeOut)
223  {
224  /* we already timed out */
225  retval = SCARD_E_TIMEOUT;
226  break;
227  }
228 
229  /* remaining time to wait */
230  delta = timeOut - delta;
231 
232  read_fd.fd = filedes;
233  read_fd.events = POLLIN;
234  read_fd.revents = 0;
235 
236  pollret = poll(&read_fd, 1, delta);
237 
238  /* try to read only when socket is readable */
239  if (pollret > 0)
240  {
241  ssize_t bytes_read;
242 
243  if (!(read_fd.revents & POLLIN))
244  {
245  /* very strange situation. it should be an assert really */
246  retval = SCARD_F_COMM_ERROR;
247  break;
248  }
249  bytes_read = read(filedes, buffer, remaining);
250 
251  if (bytes_read > 0)
252  {
253  /* we got something */
254  buffer += bytes_read;
255  remaining -= bytes_read;
256  } else if (bytes_read == 0)
257  {
258  /* peer closed the socket */
259  retval = SCARD_F_COMM_ERROR;
260  break;
261  } else
262  {
263  /* we ignore the signals and empty socket situations, all
264  * other errors are fatal */
265  if (errno != EINTR && errno != EAGAIN)
266  {
267  retval = SCARD_F_COMM_ERROR;
268  break;
269  }
270  }
271  } else if (pollret == 0)
272  {
273  /* is the daemon still there? */
274  retval = SCardCheckDaemonAvailability();
275  if (retval != SCARD_S_SUCCESS)
276  {
277  /* timeout */
278  break;
279  }
280 
281  /* you need to set the env variable PCSCLITE_DEBUG=0 since
282  * this is logged on the client side and not on the pcscd
283  * side*/
284 #ifdef NO_LOG
285  (void)command;
286 #endif
287  Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command);
288  } else
289  {
290  /* we ignore signals, all other errors are fatal */
291  if (errno != EINTR)
292  {
293  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
294  strerror(errno));
295  retval = SCARD_F_COMM_ERROR;
296  break;
297  }
298  }
299  }
300 
301  return retval;
302 }
303 
318 INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID,
319  uint64_t size, void *data_void)
320 {
321  struct rxHeader header;
322  LONG ret;
323 
324  /* header */
325  header.command = command;
326  header.size = size;
327  ret = MessageSend(&header, sizeof(header), dwClientID);
328 
329  /* command */
330  if (size > 0)
331  ret = MessageSend(data_void, size, dwClientID);
332 
333  return ret;
334 }
335 
336 #endif
337 
338 /* functions used by pcscd and libpcsclite */
339 
355 INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
356  int32_t filedes)
357 {
358  char *buffer = buffer_void;
359 
360  /* default is success */
361  LONG retval = SCARD_S_SUCCESS;
362 
363  /* how many bytes remains to be written */
364  size_t remaining = buffer_size;
365 
366  /* repeat until all data is written */
367  while (remaining > 0)
368  {
369  struct pollfd write_fd;
370  int pollret;
371 
372  write_fd.fd = filedes;
373  write_fd.events = POLLOUT;
374  write_fd.revents = 0;
375 
376  pollret = poll(&write_fd, 1, -1);
377 
378  /* try to write only when the file descriptor is writable */
379  if (pollret > 0)
380  {
381  ssize_t written;
382 
383  if (!(write_fd.revents & POLLOUT))
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 (pollret == 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 
455 INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
456  int32_t filedes)
457 {
458  char *buffer = buffer_void;
459 
460  /* default is success */
461  LONG retval = SCARD_S_SUCCESS;
462 
463  /* how many bytes we must read */
464  size_t remaining = buffer_size;
465 
466  /* repeat until we get the whole message */
467  while (remaining > 0)
468  {
469  struct pollfd read_fd;
470  int pollret;
471 
472  read_fd.fd = filedes;
473  read_fd.events = POLLIN;
474  read_fd.revents = 0;
475 
476  pollret = poll(&read_fd, 1 , -1);
477 
478  /* try to read only when socket is readable */
479  if (pollret > 0)
480  {
481  ssize_t bytes_read;
482 
483  if (!(read_fd.revents & POLLIN))
484  {
485  /* very strange situation. it should be an assert really */
486  retval = SCARD_F_COMM_ERROR;
487  break;
488  }
489  bytes_read = read(filedes, buffer, remaining);
490 
491  if (bytes_read > 0)
492  {
493  /* we got something */
494  buffer += bytes_read;
495  remaining -= bytes_read;
496  } else if (bytes_read == 0)
497  {
498  /* peer closed the socket */
499  retval = SCARD_F_COMM_ERROR;
500  break;
501  } else
502  {
503  /* we ignore the signals and empty socket situations, all
504  * other errors are fatal */
505  if (errno != EINTR && errno != EAGAIN)
506  {
507  /* connection reset by pcscd? */
508  if (ECONNRESET == errno)
510  else
511  retval = SCARD_F_COMM_ERROR;
512  break;
513  }
514  }
515  }
516  else
517  {
518  /* we ignore signals, all other errors are fatal */
519  if (errno != EINTR)
520  {
521  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
522  strerror(errno));
523  retval = SCARD_F_COMM_ERROR;
524  break;
525  }
526  }
527  }
528 
529  return retval;
530 }
531 
MessageReceiveTimeout
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:195
debuglog.h
This handles debugging.
SCARD_S_SUCCESS
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
MessageSendWithHeader
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:318
SYS_GetEnv
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
Definition: sys_unix.c:168
sys_generic.h
This handles abstract system level calls.
rxHeader
header structure for client/server message data exchange.
Definition: winscard_msg.h:68
ClientCloseSession
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:173
rxHeader::command
uint32_t command
one of the pcsc_msg_commands
Definition: winscard_msg.h:70
SCARD_W_SECURITY_VIOLATION
#define SCARD_W_SECURITY_VIOLATION
Access was denied because of a security violation.
Definition: pcsclite.h:222
SCardCheckDaemonAvailability
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
Definition: winscard_clnt.c:3546
rxHeader::size
uint32_t size
size of the message excluding this header
Definition: winscard_msg.h:69
winscard_msg.h
This defines some structures and #defines to be used over the transport layer.
SCARD_E_TIMEOUT
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
Definition: pcsclite.h:127
MessageReceive
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:455
ClientSetupSession
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
Definition: winscard_msg.c:119
winscard.h
This handles smart card reader communications.
MessageSend
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:355
time_sub
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
SCARD_F_COMM_ERROR
#define SCARD_F_COMM_ERROR
An internal communications error has been detected.
Definition: pcsclite.h:145
SCARD_E_NO_SERVICE
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
Definition: pcsclite.h:165