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 void ClientCloseSession(uint32_t dwClientID)
173 {
174  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 #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 
354 INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size,
355  int32_t filedes)
356 {
357  char *buffer = buffer_void;
358 
359  /* default is success */
360  LONG retval = SCARD_S_SUCCESS;
361 
362  /* how many bytes remains to be written */
363  size_t remaining = buffer_size;
364 
365  /* repeat until all data is written */
366  while (remaining > 0)
367  {
368  fd_set write_fd;
369  int selret;
370 
371  FD_ZERO(&write_fd);
372  FD_SET(filedes, &write_fd);
373 
374  selret = select(filedes + 1, NULL, &write_fd, NULL, NULL);
375 
376  /* try to write only when the file descriptor is writable */
377  if (selret > 0)
378  {
379  int written;
380 
381  if (!FD_ISSET(filedes, &write_fd))
382  {
383  /* very strange situation. it should be an assert really */
384  retval = SCARD_F_COMM_ERROR;
385  break;
386  }
387  /* since we are a user library we can't play with signals
388  * The signals may already be used by the application */
389 #ifdef MSG_NOSIGNAL
390  /* Get EPIPE return code instead of SIGPIPE signal
391  * Works on Linux */
392  written = send(filedes, buffer, remaining, MSG_NOSIGNAL);
393 #else
394  /* we may get a SIGPIPE signal if the other side has closed */
395  written = write(filedes, buffer, remaining);
396 #endif
397 
398  if (written > 0)
399  {
400  /* we wrote something */
401  buffer += written;
402  remaining -= written;
403  } else if (written == 0)
404  {
405  /* peer closed the socket */
406  retval = SCARD_F_COMM_ERROR;
407  break;
408  } else
409  {
410  /* we ignore the signals and socket full situations, all
411  * other errors are fatal */
412  if (errno != EINTR && errno != EAGAIN)
413  {
414  retval = SCARD_E_NO_SERVICE;
415  break;
416  }
417  }
418  } else if (selret == 0)
419  {
420  /* timeout */
421  retval = SCARD_E_TIMEOUT;
422  break;
423  } else
424  {
425  /* ignore signals */
426  if (errno != EINTR)
427  {
428  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
429  strerror(errno));
430  retval = SCARD_F_COMM_ERROR;
431  break;
432  }
433  }
434  }
435 
436  return retval;
437 }
438 
452 INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size,
453  int32_t filedes)
454 {
455  char *buffer = buffer_void;
456 
457  /* default is success */
458  LONG retval = SCARD_S_SUCCESS;
459 
460  /* how many bytes we must read */
461  size_t remaining = buffer_size;
462 
463  /* repeat until we get the whole message */
464  while (remaining > 0)
465  {
466  fd_set read_fd;
467  int selret;
468 
469  FD_ZERO(&read_fd);
470  FD_SET(filedes, &read_fd);
471 
472  selret = select(filedes + 1, &read_fd, NULL, NULL, NULL);
473 
474  /* try to read only when socket is readable */
475  if (selret > 0)
476  {
477  int readed;
478 
479  if (!FD_ISSET(filedes, &read_fd))
480  {
481  /* very strange situation. it should be an assert really */
482  retval = SCARD_F_COMM_ERROR;
483  break;
484  }
485  readed = read(filedes, buffer, remaining);
486 
487  if (readed > 0)
488  {
489  /* we got something */
490  buffer += readed;
491  remaining -= readed;
492  } else if (readed == 0)
493  {
494  /* peer closed the socket */
495  retval = SCARD_F_COMM_ERROR;
496  break;
497  } else
498  {
499  /* we ignore the signals and empty socket situations, all
500  * other errors are fatal */
501  if (errno != EINTR && errno != EAGAIN)
502  {
503  retval = SCARD_F_COMM_ERROR;
504  break;
505  }
506  }
507  }
508  else
509  {
510  /* we ignore signals, all other errors are fatal */
511  if (errno != EINTR)
512  {
513  Log2(PCSC_LOG_ERROR, "select returns with failure: %s",
514  strerror(errno));
515  retval = SCARD_F_COMM_ERROR;
516  break;
517  }
518  }
519  }
520 
521  return retval;
522 }
523 
#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:172
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
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:452
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:354
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.