pcsc-lite  1.8.20
winscard_msg.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://pcsclite.alioth.debian.org/pcsclite.html )
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 char *getSocketName(void)
83 {
84  static char socketName[sizeof(struct sockaddr_un)];
85 
86  if ('\0' == socketName[0])
87  {
88  /* socket name not yet initialized */
89  char *socketNameEnv;
90 
91  socketNameEnv = getenv("PCSCLITE_CSOCK_NAME");
92  if (socketNameEnv)
93  strncpy(socketName, socketNameEnv, sizeof(socketName));
94  else
95  strncpy(socketName, PCSCLITE_CSOCK_NAME, sizeof(socketName));
96 
97  /* Ensure a NUL byte */
98  socketName[sizeof socketName -1] = '\0';
99  }
100 
101  return socketName;
102 }
103 
117 INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
118 {
119  struct sockaddr_un svc_addr;
120  int ret;
121  char *socketName;
122 
123  ret = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
124  if (ret < 0)
125  {
126  Log2(PCSC_LOG_CRITICAL, "Error: create on client socket: %s",
127  strerror(errno));
128  return -1;
129  }
130  *pdwClientID = ret;
131 
132  socketName = getSocketName();
133  svc_addr.sun_family = AF_UNIX;
134  strncpy(svc_addr.sun_path, socketName, sizeof(svc_addr.sun_path));
135 
136  if (connect(*pdwClientID, (struct sockaddr *) &svc_addr,
137  sizeof(svc_addr.sun_family) + strlen(svc_addr.sun_path) + 1) < 0)
138  {
139  Log3(PCSC_LOG_CRITICAL, "Error: connect to client socket %s: %s",
140  socketName, strerror(errno));
141  (void)close(*pdwClientID);
142  return -1;
143  }
144 
145  ret = fcntl(*pdwClientID, F_GETFL, 0);
146  if (ret < 0)
147  {
148  Log3(PCSC_LOG_CRITICAL, "Error: cannot retrieve socket %s flags: %s",
149  socketName, strerror(errno));
150  (void)close(*pdwClientID);
151  return -1;
152  }
153 
154  if (fcntl(*pdwClientID, F_SETFL, ret | O_NONBLOCK) < 0)
155  {
156  Log3(PCSC_LOG_CRITICAL, "Error: cannot set socket %s nonblocking: %s",
157  socketName, strerror(errno));
158  (void)close(*pdwClientID);
159  return -1;
160  }
161 
162  return 0;
163 }
164 
172 INTERNAL int ClientCloseSession(uint32_t dwClientID)
173 {
174  return close(dwClientID);
175 }
176 
193 INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void,
194  uint64_t buffer_size, int32_t filedes, long timeOut)
195 {
196  char *buffer = buffer_void;
197 
198  /* default is success */
199  LONG retval = SCARD_S_SUCCESS;
200 
201  /* record the time when we started */
202  struct timeval start;
203 
204  /* how many bytes we must read */
205  size_t remaining = buffer_size;
206 
207  gettimeofday(&start, NULL);
208 
209  /* repeat until we get the whole message */
210  while (remaining > 0)
211  {
212  fd_set read_fd;
213  struct timeval timeout, now;
214  int selret;
215  long delta;
216 
217  gettimeofday(&now, NULL);
218  delta = time_sub(&now, &start);
219 
220  if (delta > timeOut*1000)
221  {
222  /* we already timed out */
223  retval = SCARD_E_TIMEOUT;
224  break;
225  }
226 
227  /* remaining time to wait */
228  delta = timeOut*1000 - delta;
229 
230  FD_ZERO(&read_fd);
231  FD_SET(filedes, &read_fd);
232 
233  timeout.tv_sec = delta/1000000;
234  timeout.tv_usec = delta - timeout.tv_sec*1000000;
235 
236  selret = select(filedes + 1, &read_fd, NULL, NULL, &timeout);
237 
238  /* try to read only when socket is readable */
239  if (selret > 0)
240  {
241  int readed;
242 
243  if (!FD_ISSET(filedes, &read_fd))
244  {
245  /* very strange situation. it should be an assert really */
246  retval = SCARD_F_COMM_ERROR;
247  break;
248  }
249  readed = read(filedes, buffer, remaining);
250 
251  if (readed > 0)
252  {
253  /* we got something */
254  buffer += readed;
255  remaining -= readed;
256  } else if (readed == 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 (selret == 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  Log2(PCSC_LOG_INFO, "Command 0x%X not yet finished", command);
285  } else
286  {
287  /* we ignore signals, all other errors are fatal */
288  if (errno != EINTR)
289  {
290  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
291  strerror(errno));
292  retval = SCARD_F_COMM_ERROR;
293  break;
294  }
295  }
296  }
297 
298  return retval;
299 }
300 
315 INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID,
316  uint64_t size, void *data_void)
317 {
318  struct rxHeader header;
319  LONG ret;
320 
321  /* header */
322  header.command = command;
323  header.size = size;
324  ret = MessageSend(&header, sizeof(header), dwClientID);
325 
326  /* command */
327  if (size > 0)
328  ret = MessageSend(data_void, size, dwClientID);
329 
330  return ret;
331 }
332 
333 #endif
334 
335 /* functions used by pcscd and libpcsclite */
336 
351 INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
352  int32_t filedes)
353 {
354  char *buffer = buffer_void;
355 
356  /* default is success */
357  LONG retval = SCARD_S_SUCCESS;
358 
359  /* how many bytes remains to be written */
360  size_t remaining = buffer_size;
361 
362  /* repeat until all data is written */
363  while (remaining > 0)
364  {
365  fd_set write_fd;
366  int selret;
367 
368  FD_ZERO(&write_fd);
369  FD_SET(filedes, &write_fd);
370 
371  selret = select(filedes + 1, NULL, &write_fd, NULL, NULL);
372 
373  /* try to write only when the file descriptor is writable */
374  if (selret > 0)
375  {
376  int written;
377 
378  if (!FD_ISSET(filedes, &write_fd))
379  {
380  /* very strange situation. it should be an assert really */
381  retval = SCARD_F_COMM_ERROR;
382  break;
383  }
384  /* since we are a user library we can't play with signals
385  * The signals may already be used by the application */
386 #ifdef MSG_NOSIGNAL
387  /* Get EPIPE return code instead of SIGPIPE signal
388  * Works on Linux */
389  written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
390 #else
391  /* we may get a SIGPIPE signal if the other side has closed */
392  written = write(filedes, buffer, remaining);
393 #endif
394 
395  if (written > 0)
396  {
397  /* we wrote something */
398  buffer += written;
399  remaining -= written;
400  } else if (written == 0)
401  {
402  /* peer closed the socket */
403  retval = SCARD_F_COMM_ERROR;
404  break;
405  } else
406  {
407  /* we ignore the signals and socket full situations, all
408  * other errors are fatal */
409  if (errno != EINTR && errno != EAGAIN)
410  {
411  retval = SCARD_E_NO_SERVICE;
412  break;
413  }
414  }
415  } else if (selret == 0)
416  {
417  /* timeout */
418  retval = SCARD_E_TIMEOUT;
419  break;
420  } else
421  {
422  /* ignore signals */
423  if (errno != EINTR)
424  {
425  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
426  strerror(errno));
427  retval = SCARD_F_COMM_ERROR;
428  break;
429  }
430  }
431  }
432 
433  return retval;
434 }
435 
449 INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
450  int32_t filedes)
451 {
452  char *buffer = buffer_void;
453 
454  /* default is success */
455  LONG retval = SCARD_S_SUCCESS;
456 
457  /* how many bytes we must read */
458  size_t remaining = buffer_size;
459 
460  /* repeat until we get the whole message */
461  while (remaining > 0)
462  {
463  fd_set read_fd;
464  int selret;
465 
466  FD_ZERO(&read_fd);
467  FD_SET(filedes, &read_fd);
468 
469  selret = select(filedes + 1, &read_fd, NULL, NULL, NULL);
470 
471  /* try to read only when socket is readable */
472  if (selret > 0)
473  {
474  int readed;
475 
476  if (!FD_ISSET(filedes, &read_fd))
477  {
478  /* very strange situation. it should be an assert really */
479  retval = SCARD_F_COMM_ERROR;
480  break;
481  }
482  readed = read(filedes, buffer, remaining);
483 
484  if (readed > 0)
485  {
486  /* we got something */
487  buffer += readed;
488  remaining -= readed;
489  } else if (readed == 0)
490  {
491  /* peer closed the socket */
492  retval = SCARD_F_COMM_ERROR;
493  break;
494  } else
495  {
496  /* we ignore the signals and empty socket situations, all
497  * other errors are fatal */
498  if (errno != EINTR && errno != EAGAIN)
499  {
500  retval = SCARD_F_COMM_ERROR;
501  break;
502  }
503  }
504  }
505  else
506  {
507  /* we ignore signals, all other errors are fatal */
508  if (errno != EINTR)
509  {
510  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
511  strerror(errno));
512  retval = SCARD_F_COMM_ERROR;
513  break;
514  }
515  }
516  }
517 
518  return retval;
519 }
520 
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
INTERNAL int ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
Definition: winscard_msg.c:172
#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 LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
Definition: winscard_msg.c:315
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:449
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:117
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:351
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:193
This handles debugging.